Bell 32V development
authorTom London <tbl@research.uucp>
Tue, 23 Jan 1979 10:53:34 +0000 (05:53 -0500)
committerTom London <tbl@research.uucp>
Tue, 23 Jan 1979 10:53:34 +0000 (05:53 -0500)
Work on file usr/src/slowsys/sys/locore.s
Work on file usr/src/slowsys/sys/acct.c
Work on file usr/src/slowsys/sys/alloc.c
Work on file usr/src/slowsys/sys/bio.c
Work on file usr/src/slowsys/sys/clock.c
Work on file usr/src/slowsys/sys/dkleave.c
Work on file usr/src/slowsys/sys/dsort.c
Work on file usr/src/slowsys/sys/fio.c
Work on file usr/src/slowsys/sys/ht.c
Work on file usr/src/slowsys/sys/iget.c
Work on file usr/src/slowsys/sys/machdep.c
Work on file usr/src/slowsys/sys/main.c
Work on file usr/src/slowsys/sys/malloc.c
Work on file usr/src/slowsys/sys/mba.c
Work on file usr/src/slowsys/sys/mem.c
Work on file usr/src/slowsys/sys/mx1.c
Work on file usr/src/slowsys/sys/mx2.c
Work on file usr/src/slowsys/sys/nami.c
Work on file usr/src/slowsys/sys/partab.c
Work on file usr/src/slowsys/sys/pipe.c
Work on file usr/src/slowsys/sys/prf.c
Work on file usr/src/slowsys/sys/prim.c
Work on file usr/src/slowsys/sys/rdwri.c
Work on file usr/src/slowsys/sys/slp.c
Work on file usr/src/slowsys/sys/subr.c
Work on file usr/src/slowsys/sys/sys1.c
Work on file usr/src/slowsys/sys/sys2.c
Work on file usr/src/slowsys/sys/sys3.c
Work on file usr/src/slowsys/sys/sys4.c
Work on file usr/src/slowsys/sys/sysent.c
Work on file usr/src/slowsys/sys/tdump.c
Work on file usr/src/slowsys/sys/text.c
Work on file usr/src/slowsys/sys/trap.c
Work on file usr/src/slowsys/sys/tty.c
Work on file usr/src/slowsys/sys/uba.c
Work on file usr/src/slowsys/sys/ureg.c
Work on file usr/src/slowsys/sys/v45lnk.c

Co-Authored-By: John Reiser <jfr@research.uucp>
Synthesized-from: 32v

37 files changed:
usr/src/slowsys/sys/acct.c [new file with mode: 0644]
usr/src/slowsys/sys/alloc.c [new file with mode: 0644]
usr/src/slowsys/sys/bio.c [new file with mode: 0644]
usr/src/slowsys/sys/clock.c [new file with mode: 0644]
usr/src/slowsys/sys/dkleave.c [new file with mode: 0644]
usr/src/slowsys/sys/dsort.c [new file with mode: 0644]
usr/src/slowsys/sys/fio.c [new file with mode: 0644]
usr/src/slowsys/sys/ht.c [new file with mode: 0644]
usr/src/slowsys/sys/iget.c [new file with mode: 0644]
usr/src/slowsys/sys/locore.s [new file with mode: 0644]
usr/src/slowsys/sys/machdep.c [new file with mode: 0644]
usr/src/slowsys/sys/main.c [new file with mode: 0644]
usr/src/slowsys/sys/malloc.c [new file with mode: 0644]
usr/src/slowsys/sys/mba.c [new file with mode: 0644]
usr/src/slowsys/sys/mem.c [new file with mode: 0644]
usr/src/slowsys/sys/mx1.c [new file with mode: 0644]
usr/src/slowsys/sys/mx2.c [new file with mode: 0644]
usr/src/slowsys/sys/nami.c [new file with mode: 0644]
usr/src/slowsys/sys/partab.c [new file with mode: 0644]
usr/src/slowsys/sys/pipe.c [new file with mode: 0644]
usr/src/slowsys/sys/prf.c [new file with mode: 0644]
usr/src/slowsys/sys/prim.c [new file with mode: 0644]
usr/src/slowsys/sys/rdwri.c [new file with mode: 0644]
usr/src/slowsys/sys/slp.c [new file with mode: 0644]
usr/src/slowsys/sys/subr.c [new file with mode: 0644]
usr/src/slowsys/sys/sys1.c [new file with mode: 0644]
usr/src/slowsys/sys/sys2.c [new file with mode: 0644]
usr/src/slowsys/sys/sys3.c [new file with mode: 0644]
usr/src/slowsys/sys/sys4.c [new file with mode: 0644]
usr/src/slowsys/sys/sysent.c [new file with mode: 0644]
usr/src/slowsys/sys/tdump.c [new file with mode: 0644]
usr/src/slowsys/sys/text.c [new file with mode: 0644]
usr/src/slowsys/sys/trap.c [new file with mode: 0644]
usr/src/slowsys/sys/tty.c [new file with mode: 0644]
usr/src/slowsys/sys/uba.c [new file with mode: 0644]
usr/src/slowsys/sys/ureg.c [new file with mode: 0644]
usr/src/slowsys/sys/v45lnk.c [new file with mode: 0644]

diff --git a/usr/src/slowsys/sys/acct.c b/usr/src/slowsys/sys/acct.c
new file mode 100644 (file)
index 0000000..ec3f04f
--- /dev/null
@@ -0,0 +1,127 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/acct.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+
+/*
+ * Perform process accounting functions.
+ */
+
+sysacct()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (suser()) {
+               if (uap->fname==NULL) {
+                       if (acctp) {
+                               plock(acctp);
+                               iput(acctp);
+                               acctp = NULL;
+                       }
+                       return;
+               }
+               if (acctp) {
+                       u.u_error = EBUSY;
+                       return;
+               }
+               ip = namei(uchar, 0);
+               if(ip == NULL)
+                       return;
+               if((ip->i_mode & IFMT) != IFREG) {
+                       u.u_error = EACCES;
+                       iput(ip);
+                       return;
+               }
+               acctp = ip;
+               prele(ip);
+       }
+}
+
+/*
+ * On exit, write a record on the accounting file.
+ */
+acct()
+{
+       register i;
+       register struct inode *ip;
+       off_t siz;
+
+       if ((ip=acctp)==NULL)
+               return;
+       plock(ip);
+       for (i=0; i<sizeof(acctbuf.ac_comm); i++)
+               acctbuf.ac_comm[i] = u.u_comm[i];
+       acctbuf.ac_utime = compress(u.u_utime);
+       acctbuf.ac_stime = compress(u.u_stime);
+       acctbuf.ac_etime = compress(time - u.u_start);
+       acctbuf.ac_btime = u.u_start;
+       acctbuf.ac_uid = u.u_ruid;
+       acctbuf.ac_gid = u.u_rgid;
+       acctbuf.ac_mem = 0;
+       acctbuf.ac_io = 0;
+       acctbuf.ac_tty = u.u_ttyd;
+       acctbuf.ac_flag = u.u_acflag;
+       siz = ip->i_size;
+       u.u_offset = siz;
+       u.u_base = (caddr_t)&acctbuf;
+       u.u_count = sizeof(acctbuf);
+       u.u_segflg = 1;
+       u.u_error = 0;
+       writei(ip);
+       if(u.u_error)
+               ip->i_size = siz;
+       prele(ip);
+}
+
+/*
+ * Produce a pseudo-floating point representation
+ * with 3 bits base-8 exponent, 13 bits fraction.
+ */
+compress(t)
+register time_t t;
+{
+       register exp = 0, round = 0;
+
+       while (t >= 8192) {
+               exp++;
+               round = t&04;
+               t >>= 3;
+       }
+       if (round) {
+               t++;
+               if (t >= 8192) {
+                       t >>= 3;
+                       exp++;
+               }
+       }
+       return((exp<<13) + t);
+}
+
+/*
+ * lock user into core as much
+ * as possible. swapping may still
+ * occur if core grows.
+ */
+syslock()
+{
+       register struct proc *p;
+       register struct a {
+               int     flag;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if(suser()) {
+               p = u.u_procp;
+               p->p_flag &= ~SULOCK;
+               if(uap->flag)
+                       p->p_flag |= SULOCK;
+       }
+}
diff --git a/usr/src/slowsys/sys/alloc.c b/usr/src/slowsys/sys/alloc.c
new file mode 100644 (file)
index 0000000..e3b1818
--- /dev/null
@@ -0,0 +1,317 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mount.h"
+#include "../h/filsys.h"
+#include "../h/fblk.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/inode.h"
+#include "../h/ino.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+typedef        struct fblk *FBLKP;
+
+/*
+ * alloc will obtain the next available
+ * free disk block from the free list of
+ * the specified device.
+ * The super block has up to NICFREE remembered
+ * free blocks; the last of these is read to
+ * obtain NICFREE more . . .
+ *
+ * no space on dev x/y -- when
+ * the free list is exhausted.
+ */
+struct buf *
+alloc(dev)
+dev_t dev;
+{
+       daddr_t bno;
+       register struct filsys *fp;
+       register struct buf *bp;
+
+       fp = getfs(dev);
+       while(fp->s_flock)
+               sleep((caddr_t)&fp->s_flock, PINOD);
+       do {
+               if(fp->s_nfree <= 0)
+                       goto nospace;
+               if (fp->s_nfree > NICFREE) {
+                       prdev("Bad free count", dev);
+                       goto nospace;
+               }
+               bno = fp->s_free[--fp->s_nfree];
+               if(bno == 0)
+                       goto nospace;
+       } while (badblock(fp, bno, dev));
+       if(fp->s_nfree <= 0) {
+               fp->s_flock++;
+               bp = bread(dev, bno);
+               if ((bp->b_flags&B_ERROR) == 0) {
+                       fp->s_nfree = ((FBLKP)(bp->b_un.b_addr))->df_nfree;
+                       bcopy((caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
+                           (caddr_t)fp->s_free, sizeof(fp->s_free));
+               }
+               brelse(bp);
+               fp->s_flock = 0;
+               wakeup((caddr_t)&fp->s_flock);
+               if (fp->s_nfree <=0)
+                       goto nospace;
+       }
+       bp = getblk(dev, bno);
+       clrbuf(bp);
+       fp->s_fmod = 1;
+       return(bp);
+
+nospace:
+       fp->s_nfree = 0;
+       prdev("no space", dev);
+       u.u_error = ENOSPC;
+       return(NULL);
+}
+
+/*
+ * place the specified disk block
+ * back on the free list of the
+ * specified device.
+ */
+free(dev, bno)
+dev_t dev;
+daddr_t bno;
+{
+       register struct filsys *fp;
+       register struct buf *bp;
+
+       fp = getfs(dev);
+       fp->s_fmod = 1;
+       while(fp->s_flock)
+               sleep((caddr_t)&fp->s_flock, PINOD);
+       if (badblock(fp, bno, dev))
+               return;
+       if(fp->s_nfree <= 0) {
+               fp->s_nfree = 1;
+               fp->s_free[0] = 0;
+       }
+       if(fp->s_nfree >= NICFREE) {
+               fp->s_flock++;
+               bp = getblk(dev, bno);
+               ((FBLKP)(bp->b_un.b_addr))->df_nfree = fp->s_nfree;
+               bcopy((caddr_t)fp->s_free,
+                       (caddr_t)((FBLKP)(bp->b_un.b_addr))->df_free,
+                       sizeof(fp->s_free));
+               fp->s_nfree = 0;
+               bwrite(bp);
+               fp->s_flock = 0;
+               wakeup((caddr_t)&fp->s_flock);
+       }
+       fp->s_free[fp->s_nfree++] = bno;
+       fp->s_fmod = 1;
+}
+
+/*
+ * Check that a block number is in the
+ * range between the I list and the size
+ * of the device.
+ * This is used mainly to check that a
+ * garbage file system has not been mounted.
+ *
+ * bad block on dev x/y -- not in range
+ */
+badblock(fp, bn, dev)
+register struct filsys *fp;
+daddr_t bn;
+dev_t dev;
+{
+
+       if (bn < fp->s_isize || bn >= fp->s_fsize) {
+               prdev("bad block", dev);
+               return(1);
+       }
+       return(0);
+}
+
+/*
+ * Allocate an unused I node
+ * on the specified device.
+ * Used with file creation.
+ * The algorithm keeps up to
+ * NICINOD spare I nodes in the
+ * super block. When this runs out,
+ * a linear search through the
+ * I list is instituted to pick
+ * up NICINOD more.
+ */
+struct inode *
+ialloc(dev)
+dev_t dev;
+{
+       register struct filsys *fp;
+       register struct buf *bp;
+       register struct inode *ip;
+       int i;
+       struct dinode *dp;
+       ino_t ino;
+       daddr_t adr;
+
+       fp = getfs(dev);
+       while(fp->s_ilock)
+               sleep((caddr_t)&fp->s_ilock, PINOD);
+loop:
+       if(fp->s_ninode > 0) {
+               ino = fp->s_inode[--fp->s_ninode];
+               ip = iget(dev, ino);
+               if(ip == NULL)
+                       return(NULL);
+               if(ip->i_mode == 0) {
+                       for (i=0; i<NADDR; i++)
+                               ip->i_un.i_addr[i] = 0;
+                       fp->s_fmod = 1;
+                       return(ip);
+               }
+               /*
+                * Inode was allocated after all.
+                * Look some more.
+                */
+               iput(ip);
+               goto loop;
+       }
+       fp->s_ilock++;
+       ino = 1;
+       for(adr = SUPERB+1; adr < fp->s_isize; adr++) {
+               bp = bread(dev, adr);
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       ino += INOPB;
+                       continue;
+               }
+               dp = bp->b_un.b_dino;
+               for(i=0; i<INOPB; i++) {
+                       if(dp->di_mode != 0)
+                               goto cont;
+                       for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
+                       if(dev==ip->i_dev && ino==ip->i_number)
+                               goto cont;
+                       fp->s_inode[fp->s_ninode++] = ino;
+                       if(fp->s_ninode >= NICINOD)
+                               break;
+               cont:
+                       ino++;
+                       dp++;
+               }
+               brelse(bp);
+               if(fp->s_ninode >= NICINOD)
+                       break;
+       }
+       fp->s_ilock = 0;
+       wakeup((caddr_t)&fp->s_ilock);
+       if(fp->s_ninode > 0)
+               goto loop;
+       prdev("Out of inodes", dev);
+       u.u_error = ENOSPC;
+       return(NULL);
+}
+
+/*
+ * Free the specified I node
+ * on the specified device.
+ * The algorithm stores up
+ * to NICINOD I nodes in the super
+ * block and throws away any more.
+ */
+ifree(dev, ino)
+dev_t dev;
+ino_t ino;
+{
+       register struct filsys *fp;
+
+       fp = getfs(dev);
+       if(fp->s_ilock)
+               return;
+       if(fp->s_ninode >= NICINOD)
+               return;
+       fp->s_inode[fp->s_ninode++] = ino;
+       fp->s_fmod = 1;
+}
+
+/*
+ * getfs maps a device number into
+ * a pointer to the incore super
+ * block.
+ * The algorithm is a linear
+ * search through the mount table.
+ * A consistency check of the
+ * in core free-block and i-node
+ * counts.
+ *
+ * bad count on dev x/y -- the count
+ *     check failed. At this point, all
+ *     the counts are zeroed which will
+ *     almost certainly lead to "no space"
+ *     diagnostic
+ * panic: no fs -- the device is not mounted.
+ *     this "cannot happen"
+ */
+struct filsys *
+getfs(dev)
+dev_t dev;
+{
+       register struct mount *mp;
+       register struct filsys *fp;
+
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+       if(mp->m_bufp != NULL && mp->m_dev == dev) {
+               fp = mp->m_bufp->b_un.b_filsys;
+               if(fp->s_nfree > NICFREE || fp->s_ninode > NICINOD) {
+                       prdev("bad count", dev);
+                       fp->s_nfree = 0;
+                       fp->s_ninode = 0;
+               }
+               return(fp);
+       }
+       panic("no fs");
+       return(NULL);
+}
+
+/*
+ * update is the internal name of
+ * 'sync'. It goes through the disk
+ * queues to initiate sandbagged IO;
+ * goes through the I nodes to write
+ * modified nodes; and it goes through
+ * the mount table to initiate modified
+ * super blocks.
+ */
+update()
+{
+       register struct inode *ip;
+       register struct mount *mp;
+       register struct buf *bp;
+       struct filsys *fp;
+
+       if(updlock)
+               return;
+       updlock++;
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+               if(mp->m_bufp != NULL) {
+                       fp = mp->m_bufp->b_un.b_filsys;
+                       if(fp->s_fmod==0 || fp->s_ilock!=0 ||
+                          fp->s_flock!=0 || fp->s_ronly!=0)
+                               continue;
+                       bp = getblk(mp->m_dev, SUPERB);
+                       if (bp->b_flags & B_ERROR)
+                               continue;
+                       fp->s_fmod = 0;
+                       fp->s_time = time;
+                       bcopy((caddr_t)fp, bp->b_un.b_addr, BSIZE);
+                       bwrite(bp);
+               }
+       for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
+               if((ip->i_flag&ILOCK)==0 && ip->i_count) {
+                       ip->i_flag |= ILOCK;
+                       ip->i_count++;
+                       iupdat(ip, &time, &time);
+                       iput(ip);
+               }
+       updlock = 0;
+       bflush(NODEV);
+}
diff --git a/usr/src/slowsys/sys/bio.c b/usr/src/slowsys/sys/bio.c
new file mode 100644 (file)
index 0000000..82cc3f0
--- /dev/null
@@ -0,0 +1,531 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+
+#define        DISKMON 1
+
+#ifdef DISKMON
+struct {
+       int     nbuf;
+       long    nread;
+       long    nreada;
+       long    ncache;
+       long    nwrite;
+       long    bufcount[NBUF];
+} io_info;
+#endif
+
+/*
+ * swap IO headers.
+ * they are filled in to point
+ * at the desired IO operation.
+ */
+struct buf     swbuf1;
+struct buf     swbuf2;
+
+/*
+ * The following several routines allocate and free
+ * buffers with various side effects.  In general the
+ * arguments to an allocate routine are a device and
+ * a block number, and the value is a pointer to
+ * to the buffer header; the buffer is marked "busy"
+ * so that no one else can touch it.  If the block was
+ * already in core, no I/O need be done; if it is
+ * already busy, the process waits until it becomes free.
+ * The following routines allocate a buffer:
+ *     getblk
+ *     bread
+ *     breada
+ * Eventually the buffer must be released, possibly with the
+ * side effect of writing it out, by using one of
+ *     bwrite
+ *     bdwrite
+ *     bawrite
+ *     brelse
+ */
+
+/*
+ * Read in (if necessary) the block and return a buffer pointer.
+ */
+struct buf *
+bread(dev, blkno)
+dev_t dev;
+daddr_t blkno;
+{
+       register struct buf *bp;
+
+       bp = getblk(dev, blkno);
+       if (bp->b_flags&B_DONE) {
+#ifdef DISKMON
+               io_info.ncache++;
+#endif
+               return(bp);
+       }
+       bp->b_flags |= B_READ;
+       bp->b_bcount = BSIZE;
+       (*bdevsw[major(dev)].d_strategy)(bp);
+#ifdef DISKMON
+       io_info.nread++;
+#endif
+       iowait(bp);
+       return(bp);
+}
+
+/*
+ * Read in the block, like bread, but also start I/O on the
+ * read-ahead block (which is not allocated to the caller)
+ */
+struct buf *
+breada(dev, blkno, rablkno)
+dev_t dev;
+daddr_t blkno, rablkno;
+{
+       register struct buf *bp, *rabp;
+
+       bp = NULL;
+       if (!incore(dev, blkno)) {
+               bp = getblk(dev, blkno);
+               if ((bp->b_flags&B_DONE) == 0) {
+                       bp->b_flags |= B_READ;
+                       bp->b_bcount = BSIZE;
+                       (*bdevsw[major(dev)].d_strategy)(bp);
+#ifdef DISKMON
+                       io_info.nread++;
+#endif
+               }
+       }
+       if (rablkno && !incore(dev, rablkno)) {
+               rabp = getblk(dev, rablkno);
+               if (rabp->b_flags & B_DONE)
+                       brelse(rabp);
+               else {
+                       rabp->b_flags |= B_READ|B_ASYNC;
+                       rabp->b_bcount = BSIZE;
+                       (*bdevsw[major(dev)].d_strategy)(rabp);
+#ifdef DISKMON
+                       io_info.nreada++;
+#endif
+               }
+       }
+       if(bp == NULL)
+               return(bread(dev, blkno));
+       iowait(bp);
+       return(bp);
+}
+
+/*
+ * Write the buffer, waiting for completion.
+ * Then release the buffer.
+ */
+bwrite(bp)
+register struct buf *bp;
+{
+       register flag;
+
+       flag = bp->b_flags;
+       bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE);
+       bp->b_bcount = BSIZE;
+#ifdef DISKMON
+       io_info.nwrite++;
+#endif
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       if ((flag&B_ASYNC) == 0) {
+               iowait(bp);
+               brelse(bp);
+       } else if (flag & B_DELWRI)
+               bp->b_flags |= B_AGE;
+       else
+               geterror(bp);
+}
+
+/*
+ * Release the buffer, marking it so that if it is grabbed
+ * for another purpose it will be written out before being
+ * given up (e.g. when writing a partial block where it is
+ * assumed that another write for the same block will soon follow).
+ * This can't be done for magtape, since writes must be done
+ * in the same order as requested.
+ */
+bdwrite(bp)
+register struct buf *bp;
+{
+       register struct buf *dp;
+
+       dp = bdevsw[major(bp->b_dev)].d_tab;
+       if(dp->b_flags & B_TAPE)
+               bawrite(bp);
+       else {
+               bp->b_flags |= B_DELWRI | B_DONE;
+               brelse(bp);
+       }
+}
+
+/*
+ * Release the buffer, start I/O on it, but don't wait for completion.
+ */
+bawrite(bp)
+register struct buf *bp;
+{
+
+       bp->b_flags |= B_ASYNC;
+       bwrite(bp);
+}
+
+/*
+ * release the buffer, with no I/O implied.
+ */
+brelse(bp)
+register struct buf *bp;
+{
+       register struct buf **backp;
+       register s;
+
+       if (bp->b_flags&B_WANTED)
+               wakeup((caddr_t)bp);
+       if (bfreelist.b_flags&B_WANTED) {
+               bfreelist.b_flags &= ~B_WANTED;
+               wakeup((caddr_t)&bfreelist);
+       }
+       if (bp->b_flags&B_ERROR)
+               bp->b_dev = NODEV;  /* no assoc. on error */
+       s = spl6();
+       if(bp->b_flags & B_AGE) {
+               backp = &bfreelist.av_forw;
+               (*backp)->av_back = bp;
+               bp->av_forw = *backp;
+               *backp = bp;
+               bp->av_back = &bfreelist;
+       } else {
+               backp = &bfreelist.av_back;
+               (*backp)->av_forw = bp;
+               bp->av_back = *backp;
+               *backp = bp;
+               bp->av_forw = &bfreelist;
+       }
+       bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
+       splx(s);
+}
+
+/*
+ * See if the block is associated with some buffer
+ * (mainly to avoid getting hung up on a wait in breada)
+ */
+incore(dev, blkno)
+dev_t dev;
+daddr_t blkno;
+{
+       register struct buf *bp;
+       register struct buf *dp;
+
+       dp = bdevsw[major(dev)].d_tab;
+       for (bp=dp->b_forw; bp != dp; bp = bp->b_forw)
+               if (bp->b_blkno==blkno && bp->b_dev==dev)
+                       return(1);
+       return(0);
+}
+
+/*
+ * Assign a buffer for the given block.  If the appropriate
+ * block is already associated, return it; otherwise search
+ * for the oldest non-busy buffer and reassign it.
+ */
+struct buf *
+getblk(dev, blkno)
+dev_t dev;
+daddr_t blkno;
+{
+       register struct buf *bp;
+       register struct buf *dp;
+#ifdef DISKMON
+       register i;
+#endif
+
+       if(major(dev) >= nblkdev)
+               panic("blkdev");
+
+    loop:
+       spl0();
+       dp = bdevsw[major(dev)].d_tab;
+       if(dp == NULL)
+               panic("devtab");
+       for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) {
+               if (bp->b_blkno!=blkno || bp->b_dev!=dev)
+                       continue;
+               spl6();
+               if (bp->b_flags&B_BUSY) {
+                       bp->b_flags |= B_WANTED;
+                       sleep((caddr_t)bp, PRIBIO+1);
+                       goto loop;
+               }
+               spl0();
+#ifdef DISKMON
+               i = 0;
+               dp = bp->av_forw;
+               while (dp != &bfreelist) {
+                       i++;
+                       dp = dp->av_forw;
+               }
+               if (i<NBUF)
+                       io_info.bufcount[i]++;
+#endif
+               notavail(bp);
+               return(bp);
+       }
+       spl6();
+       if (bfreelist.av_forw == &bfreelist) {
+               bfreelist.b_flags |= B_WANTED;
+               sleep((caddr_t)&bfreelist, PRIBIO+1);
+               goto loop;
+       }
+       spl0();
+       notavail(bp = bfreelist.av_forw);
+       if (bp->b_flags & B_DELWRI) {
+               bp->b_flags |= B_ASYNC;
+               bwrite(bp);
+               goto loop;
+       }
+       bp->b_flags = B_BUSY;
+       bp->b_back->b_forw = bp->b_forw;
+       bp->b_forw->b_back = bp->b_back;
+       bp->b_forw = dp->b_forw;
+       bp->b_back = dp;
+       dp->b_forw->b_back = bp;
+       dp->b_forw = bp;
+       bp->b_dev = dev;
+       bp->b_blkno = blkno;
+       return(bp);
+}
+
+/*
+ * get an empty block,
+ * not assigned to any particular device
+ */
+struct buf *
+geteblk()
+{
+       register struct buf *bp;
+       register struct buf *dp;
+
+loop:
+       spl6();
+       while (bfreelist.av_forw == &bfreelist) {
+               bfreelist.b_flags |= B_WANTED;
+               sleep((caddr_t)&bfreelist, PRIBIO+1);
+       }
+       spl0();
+       dp = &bfreelist;
+       notavail(bp = bfreelist.av_forw);
+       if (bp->b_flags & B_DELWRI) {
+               bp->b_flags |= B_ASYNC;
+               bwrite(bp);
+               goto loop;
+       }
+       bp->b_flags = B_BUSY;
+       bp->b_back->b_forw = bp->b_forw;
+       bp->b_forw->b_back = bp->b_back;
+       bp->b_forw = dp->b_forw;
+       bp->b_back = dp;
+       dp->b_forw->b_back = bp;
+       dp->b_forw = bp;
+       bp->b_dev = (dev_t)NODEV;
+       return(bp);
+}
+
+/*
+ * Wait for I/O completion on the buffer; return errors
+ * to the user.
+ */
+iowait(bp)
+register struct buf *bp;
+{
+
+       spl6();
+       while ((bp->b_flags&B_DONE)==0)
+               sleep((caddr_t)bp, PRIBIO);
+       spl0();
+       geterror(bp);
+}
+
+/*
+ * Unlink a buffer from the available list and mark it busy.
+ * (internal interface)
+ */
+notavail(bp)
+register struct buf *bp;
+{
+       register s;
+
+       s = spl6();
+       bp->av_back->av_forw = bp->av_forw;
+       bp->av_forw->av_back = bp->av_back;
+       bp->b_flags |= B_BUSY;
+       splx(s);
+}
+
+/*
+ * Mark I/O complete on a buffer, release it if I/O is asynchronous,
+ * and wake up anyone waiting for it.
+ */
+iodone(bp)
+register struct buf *bp;
+{
+
+       bp->b_flags |= B_DONE;
+       if (bp->b_flags&B_ASYNC)
+               brelse(bp);
+       else {
+               bp->b_flags &= ~B_WANTED;
+               wakeup((caddr_t)bp);
+       }
+}
+
+/*
+ * Zero the core associated with a buffer.
+ */
+clrbuf(bp)
+struct buf *bp;
+{
+       register *p;
+       register c;
+
+       p = bp->b_un.b_words;
+       c = BSIZE/sizeof(int);
+       do
+               *p++ = 0;
+       while (--c);
+       bp->b_resid = 0;
+}
+
+/*
+ * swap I/O
+ */
+swap(blkno, coreaddr, count, rdflg)
+{
+       register struct buf *bp;
+       register int c;
+
+       bp = &swbuf1;
+       if(bp->b_flags & B_BUSY)
+               if((swbuf2.b_flags&B_WANTED) == 0)
+                       bp = &swbuf2;
+       spl6();
+       while (bp->b_flags&B_BUSY) {
+               bp->b_flags |= B_WANTED;
+               sleep((caddr_t)bp, PSWP+1);
+       }
+       while (count > 0){
+               bp->b_flags = B_BUSY | B_PHYS | rdflg;
+               bp->b_dev = swapdev;
+               bp->b_bcount = ctob((c=count>120?120:count));
+               bp->b_blkno = swplo+blkno;
+               bp->b_un.b_addr = (caddr_t)ctob(coreaddr);
+               (*bdevsw[major(swapdev)].d_strategy)(bp);
+               spl6();
+               while((bp->b_flags&B_DONE)==0)
+                       sleep((caddr_t)bp, PSWP);
+               if (bp->b_flags&B_WANTED)
+                       wakeup((caddr_t)bp);
+               spl0();
+               bp->b_flags &= ~(B_BUSY|B_WANTED);
+               if (bp->b_flags & B_ERROR)
+                       panic("IO err in swap");
+               count -= c;
+               blkno += c;
+               coreaddr += c;
+       }
+       bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
+}
+
+/*
+ * make sure all write-behind blocks
+ * on dev (or NODEV for all)
+ * are flushed out.
+ * (from umount and update)
+ */
+bflush(dev)
+dev_t dev;
+{
+       register struct buf *bp;
+
+loop:
+       spl6();
+       for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) {
+               if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
+                       bp->b_flags |= B_ASYNC;
+                       notavail(bp);
+                       bwrite(bp);
+                       goto loop;
+               }
+       }
+       spl0();
+}
+
+/*
+ * Raw I/O. The arguments are
+ *     The strategy routine for the device
+ *     A buffer, which will always be a special buffer
+ *       header owned exclusively by the device for this purpose
+ *     The device number
+ *     Read/write flag
+ * Essentially all the work is computing physical addresses and
+ * validating them.
+ */
+physio(strat, bp, dev, rw)
+register struct buf *bp;
+int (*strat)();
+{
+       register caddr_t base;
+       register int c;
+
+       if ((base = checkio(rw)) == NULL)
+               return;
+       spl6();
+       while (bp->b_flags&B_BUSY) {
+               bp->b_flags |= B_WANTED;
+               sleep((caddr_t)bp, PRIBIO+1);
+       }
+       bp->b_error = 0;
+       while (u.u_count > 0 && bp->b_error==0) {
+               bp->b_flags = B_BUSY | B_PHYS | rw;
+               bp->b_dev = dev;
+               bp->b_un.b_addr = base;
+               bp->b_blkno = u.u_offset >> BSHIFT;
+               bp->b_bcount = c = u.u_count>60*1024 ? 60*1024 : u.u_count;
+               u.u_procp->p_flag |= SLOCK;
+               (*strat)(bp);
+               spl6();
+               while ((bp->b_flags&B_DONE) == 0)
+                       sleep((caddr_t)bp, PRIBIO);
+               u.u_procp->p_flag &= ~SLOCK;
+               if (bp->b_flags&B_WANTED)
+                       wakeup((caddr_t)bp);
+               spl0();
+               base += c;
+               u.u_count -= c;
+               u.u_offset += c;
+       }
+       bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
+       u.u_count = bp->b_resid;
+       geterror(bp);
+       return;
+}
+
+/*
+ * Pick up the device's error number and pass it to the user;
+ * if there is an error but the number is 0 set a generalized
+ * code.  Actually the latter is always true because devices
+ * don't yet return specific errors.
+ */
+geterror(bp)
+register struct buf *bp;
+{
+
+       if (bp->b_flags&B_ERROR)
+               if ((u.u_error = bp->b_error)==0)
+                       u.u_error = EIO;
+}
diff --git a/usr/src/slowsys/sys/clock.c b/usr/src/slowsys/sys/clock.c
new file mode 100644 (file)
index 0000000..926ea84
--- /dev/null
@@ -0,0 +1,187 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/callo.h"
+#include "../h/seg.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/reg.h"
+#include "../h/psl.h"
+
+#define        SCHMAG  8/10
+
+/*
+ * clock is called straight from
+ * the real time clock interrupt.
+ *
+ * Functions:
+ *     copy *switches to display
+ *     implement callouts
+ *     maintain user/system times
+ *     maintain date
+ *     profile
+ *     lightning bolt wakeup (every second)
+ *     alarm clock signals
+ *     jab the scheduler
+ */
+
+clock(pc, ps)
+caddr_t pc;
+{
+       register struct callo *p1, *p2;
+       register struct proc *pp;
+       int a;
+       extern caddr_t waitloc, ewaitloc;
+
+       /*
+        * reprime clock
+        */
+       clkreld();
+
+       /*
+        * keep the microsecond clock
+       */
+       add64(CLKTICK,&time64[0],&time64[1]);
+       /*
+        * display register
+        */
+       display();
+
+
+
+       /*
+        * callouts
+        * if none, just continue
+        * else update first non-zero time
+        */
+
+       if(callout[0].c_func == NULL)
+               goto out;
+       p2 = &callout[0];
+       while(p2->c_time<=0 && p2->c_func!=NULL)
+               p2++;
+       p2->c_time--;
+
+       /*
+        * if ps is high, just return
+        */
+       if (BASEPRI(ps))
+               goto out;
+
+       /*
+        * callout
+        */
+
+       if(callout[0].c_time <= 0) {
+               p1 = &callout[0];
+               while(p1->c_func != 0 && p1->c_time <= 0) {
+                       (*p1->c_func)(p1->c_arg);
+                       p1++;
+               }
+               p2 = &callout[0];
+               while(p2->c_func = p1->c_func) {
+                       p2->c_time = p1->c_time;
+                       p2->c_arg = p1->c_arg;
+                       p1++;
+                       p2++;
+               }
+       }
+
+       /*
+        * lightning bolt time-out
+        * and time of day
+        */
+out:
+       a = dk_busy&07;
+       if (USERMODE(ps)) {
+               u.u_utime++;
+               if(u.u_prof.pr_scale)
+                       addupc(pc, &u.u_prof, 1);
+               if(u.u_procp->p_nice > NZERO)
+                       a += 8;
+       } else {
+               a += 16;
+               if (pc == waitloc || pc == ewaitloc )
+                       a += 8;
+               u.u_stime++;
+       }
+       dk_time[a] += 1;
+       pp = u.u_procp;
+       if(++pp->p_cpu == 0)
+               pp->p_cpu--;
+       if(++lbolt >= HZ) {
+               if (BASEPRI(ps))
+                       return;
+               lbolt -= HZ;
+               ++time;
+               runrun++;
+               wakeup((caddr_t)&lbolt);
+               for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
+               if (pp->p_stat && pp->p_stat<SZOMB) {
+                       if(pp->p_time != 127)
+                               pp->p_time++;
+                       if(pp->p_clktim)
+                               if(--pp->p_clktim == 0)
+                                       psignal(pp, SIGCLK);
+                       a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
+                       if(a < 0)
+                               a = 0;
+                       if(a > 255)
+                               a = 255;
+                       pp->p_cpu = a;
+                       if(pp->p_pri >= PUSER)
+                               setpri(pp);
+               }
+               if(runin!=0) {
+                       runin = 0;
+                       wakeup((caddr_t)&runin);
+               }
+       }
+}
+
+/*
+ * timeout is called to arrange that
+ * fun(arg) is called in tim/HZ seconds.
+ * An entry is sorted into the callout
+ * structure. The time in each structure
+ * entry is the number of HZ's more
+ * than the previous entry.
+ * In this way, decrementing the
+ * first entry has the effect of
+ * updating all entries.
+ *
+ * The panic is there because there is nothing
+ * intelligent to be done if an entry won't fit.
+ */
+timeout(fun, arg, tim)
+int (*fun)();
+caddr_t arg;
+{
+       register struct callo *p1, *p2;
+       register int t;
+       int s;
+
+       t = tim;
+       p1 = &callout[0];
+       s = spl7();
+       while(p1->c_func != 0 && p1->c_time <= t) {
+               t -= p1->c_time;
+               p1++;
+       }
+       if (p1 >= &callout[NCALL-1])
+               panic("Timeout table overflow");
+       p1->c_time -= t;
+       p2 = p1;
+       while(p2->c_func != 0)
+               p2++;
+       while(p2 >= p1) {
+               (p2+1)->c_time = p2->c_time;
+               (p2+1)->c_func = p2->c_func;
+               (p2+1)->c_arg = p2->c_arg;
+               p2--;
+       }
+       p1->c_time = t;
+       p1->c_func = fun;
+       p1->c_arg = arg;
+       splx(s);
+}
diff --git a/usr/src/slowsys/sys/dkleave.c b/usr/src/slowsys/sys/dkleave.c
new file mode 100644 (file)
index 0000000..7cd7a7d
--- /dev/null
@@ -0,0 +1,29 @@
+#include "../h/param.h"
+#include "../h/buf.h"
+
+daddr_t
+dkblock(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       if (((dminor=minor(bp->b_dev))&0100) == 0)
+               return(bp->b_blkno);
+       dminor >>= 3;
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno/dminor);
+}
+
+dkunit(bp)
+register struct buf *bp;
+{
+       register int dminor;
+
+       dminor = minor(bp->b_dev) >> 3;
+       if ((dminor&010) == 0)
+               return(dminor);
+       dminor &= 07;
+       dminor++;
+       return(bp->b_blkno%dminor);
+}
diff --git a/usr/src/slowsys/sys/dsort.c b/usr/src/slowsys/sys/dsort.c
new file mode 100644 (file)
index 0000000..5a90c1e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * generalized seek sort for disk
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+
+#define        b_cylin b_resid
+
+disksort(dp, bp)
+register struct buf *dp, *bp;
+{
+       register struct buf *ap;
+       struct buf *tp;
+
+       ap = dp->b_actf;
+       if(ap == NULL) {
+               dp->b_actf = bp;
+               dp->b_actl = bp;
+               bp->av_forw = NULL;
+               return;
+       }
+       tp = NULL;
+       for(; ap != NULL; ap = ap->av_forw) {
+               if ((bp->b_flags&B_READ) && (ap->b_flags&B_READ) == 0) {
+                       if (tp == NULL)
+                               tp = ap;
+                       break;
+               }
+               if ((bp->b_flags&B_READ) == 0 && (ap->b_flags&B_READ))
+                       continue;
+               if(ap->b_cylin <= bp->b_cylin)
+                       if(tp == NULL || ap->b_cylin >= tp->b_cylin)
+                               tp = ap;
+       }
+       if(tp == NULL)
+               tp = dp->b_actl;
+       bp->av_forw = tp->av_forw;
+       tp->av_forw = bp;
+       if(tp == dp->b_actl)
+               dp->b_actl = bp;
+}
diff --git a/usr/src/slowsys/sys/fio.c b/usr/src/slowsys/sys/fio.c
new file mode 100644 (file)
index 0000000..3d0bd7c
--- /dev/null
@@ -0,0 +1,260 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/filsys.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/inode.h"
+#include "../h/reg.h"
+#include "../h/acct.h"
+
+/*
+ * Convert a user supplied
+ * file descriptor into a pointer
+ * to a file structure.
+ * Only task is to check range
+ * of the descriptor.
+ */
+struct file *
+getf(f)
+register int f;
+{
+       register struct file *fp;
+
+       if(0 <= f && f < NOFILE) {
+               fp = u.u_ofile[f];
+               if(fp != NULL)
+                       return(fp);
+       }
+       u.u_error = EBADF;
+       return(NULL);
+}
+
+/*
+ * Internal form of close.
+ * Decrement reference count on
+ * file structure.
+ * Also make sure the pipe protocol
+ * does not constipate.
+ *
+ * Decrement reference count on the inode following
+ * removal to the referencing file structure.
+ * On the last close switch out to the device handler for
+ * special files.  Note that the handler is called
+ * on every open but only the last close.
+ */
+closef(fp)
+register struct file *fp;
+{
+       register struct inode *ip;
+       int flag;
+       dev_t dev;
+       register int (*cfunc)();
+
+       if(fp == NULL)
+               return;
+       if (fp->f_count > 1) {
+               fp->f_count--;
+               return;
+       }
+       ip = fp->f_inode;
+       plock(ip);
+       flag = fp->f_flag&FWRITE;
+       fp->f_count = 0;
+       if(fp->f_flag & FPIPE) {
+               ip->i_mode &= ~(IREAD|IWRITE);
+               wakeup((caddr_t)ip+1);
+               wakeup((caddr_t)ip+2);
+       }
+       iput(ip);
+       dev = (dev_t)ip->i_un.i_rdev;
+       switch(ip->i_mode&IFMT) {
+
+       case IFCHR:
+       case IFMPC:
+               cfunc = cdevsw[major(dev)].d_close;
+               break;
+
+       case IFBLK:
+       case IFMPB:
+               cfunc = bdevsw[major(dev)].d_close;
+               break;
+
+       default:
+               return;
+       }
+       if (fp->f_flag&FMP) {
+               (*cfunc)(dev, fp->f_un.f_chan);
+       } else {
+               for (fp=file; fp < &file[NFILE]; fp++)
+                       if (fp->f_count && fp->f_inode==ip)
+                               return;
+               (*cfunc)(dev, flag);
+       }
+}
+
+/*
+ * openi called to allow handler
+ * of special files to initialize and
+ * validate before actual IO.
+ */
+openi(ip, rw)
+register struct inode *ip;
+{
+       dev_t dev;
+       register unsigned int maj;
+
+       dev = (dev_t)ip->i_un.i_rdev;
+       maj = major(dev);
+       switch(ip->i_mode&IFMT) {
+
+       case IFCHR:
+       case IFMPC:
+               if(maj >= nchrdev)
+                       goto bad;
+               (*cdevsw[maj].d_open)(dev, rw);
+               break;
+
+       case IFBLK:
+       case IFMPB:
+               if(maj >= nblkdev)
+                       goto bad;
+               (*bdevsw[maj].d_open)(dev, rw);
+       }
+       return;
+
+bad:
+       u.u_error = ENXIO;
+}
+
+/*
+ * Check mode permission on inode pointer.
+ * Mode is READ, WRITE or EXEC.
+ * In the case of WRITE, the
+ * read-only status of the file
+ * system is checked.
+ * Also in WRITE, prototype text
+ * segments cannot be written.
+ * The mode is shifted to select
+ * the owner/group/other fields.
+ * The super user is granted all
+ * permissions.
+ */
+access(ip, mode)
+register struct inode *ip;
+{
+       register m;
+
+       m = mode;
+       if(m == IWRITE) {
+               if(getfs(ip->i_dev)->s_ronly != 0) {
+                       u.u_error = EROFS;
+                       return(1);
+               }
+               if (ip->i_flag&ITEXT)           /* try to free text */
+                       xrele(ip);
+               if(ip->i_flag & ITEXT) {
+                       u.u_error = ETXTBSY;
+                       return(1);
+               }
+       }
+       if(u.u_uid == 0)
+               return(0);
+       if(u.u_uid != ip->i_uid) {
+               m >>= 3;
+               if(u.u_gid != ip->i_gid)
+                       m >>= 3;
+       }
+       if((ip->i_mode&m) != 0)
+               return(0);
+
+       u.u_error = EACCES;
+       return(1);
+}
+
+/*
+ * Look up a pathname and test if
+ * the resultant inode is owned by the
+ * current user.
+ * If not, try for super-user.
+ * If permission is granted,
+ * return inode pointer.
+ */
+struct inode *
+owner()
+{
+       register struct inode *ip;
+
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return(NULL);
+       if(u.u_uid == ip->i_uid)
+               return(ip);
+       if(suser())
+               return(ip);
+       iput(ip);
+       return(NULL);
+}
+
+/*
+ * Test if the current user is the
+ * super user.
+ */
+suser()
+{
+
+       if(u.u_uid == 0) {
+               u.u_acflag |= ASU;
+               return(1);
+       }
+       u.u_error = EPERM;
+       return(0);
+}
+
+/*
+ * Allocate a user file descriptor.
+ */
+ufalloc()
+{
+       register i;
+
+       for(i=0; i<NOFILE; i++)
+               if(u.u_ofile[i] == NULL) {
+                       u.u_r.r_val1 = i;
+                       u.u_pofile[i] = 0;
+                       return(i);
+               }
+       u.u_error = EMFILE;
+       return(-1);
+}
+
+/*
+ * Allocate a user file descriptor
+ * and a file structure.
+ * Initialize the descriptor
+ * to point at the file structure.
+ *
+ * no file -- if there are no available
+ *     file structures.
+ */
+struct file *
+falloc()
+{
+       register struct file *fp;
+       register i;
+
+       i = ufalloc();
+       if(i < 0)
+               return(NULL);
+       for(fp = &file[0]; fp < &file[NFILE]; fp++)
+               if(fp->f_count == 0) {
+                       u.u_ofile[i] = fp;
+                       fp->f_count++;
+                       fp->f_un.f_offset = 0;
+                       return(fp);
+               }
+       printf("no file\n");
+       u.u_error = ENFILE;
+       return(NULL);
+}
diff --git a/usr/src/slowsys/sys/ht.c b/usr/src/slowsys/sys/ht.c
new file mode 100644 (file)
index 0000000..a75f797
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * TJU16 tape driver
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/mba.h"
+
+struct device
+{
+       int     htcs1;
+       int     htds;
+       int     hter;
+       int     htmr;
+       int     htas;
+       int     htfc;
+       int     htdt;
+       int     htck;
+       int     htsn;
+       int     httc;
+};
+
+struct buf     httab;
+struct buf     rhtbuf;
+struct buf     chtbuf;
+
+#define        NUNIT   1
+#define        BUNIT   2
+#define        INF     1000000
+
+char   h_openf[NUNIT];
+daddr_t        h_blkno[NUNIT];
+daddr_t        h_nxrec[NUNIT];
+
+#define        HTADDR  ((struct device *)(MBA1 + MBA_ERB))
+
+#define        GO      01
+#define        WCOM    060
+#define        RCOM    070
+#define        NOP     0
+#define        WEOF    026
+#define        SFORW   030
+#define        SREV    032
+#define        ERASE   024
+#define        REW     06
+#define        DCLR    010
+#define P800   01700           /* 800 + pdp11 mode */
+#define        P1600   02300           /* 1600 + pdp11 mode */
+#define        IENABLE 0100
+#define        RDY     0200
+#define        TM      04
+#define        DRY     0200
+#define EOT    02000
+#define CS     02000
+#define COR    0100000
+#define PES    040
+#define WRL    04000
+#define MOL    010000
+#define ERR    040000
+#define FCE    01000
+#define        TRE     040000
+#define HARD   064023  /* UNS|OPI|NEF|FMT|RMR|ILR|ILF */
+
+#define        SIO     1
+#define        SSFOR   2
+#define        SSREV   3
+#define SRETRY 4
+#define SCOM   5
+#define SOK    6
+
+htopen(dev, flag)
+{
+       register unit, ds;
+
+       httab.b_flags |= B_TAPE;
+       unit = minor(dev) & 03;
+       if (unit >= NUNIT || h_openf[unit]) {
+               u.u_error = ENXIO;
+               return;
+       }
+       h_blkno[unit] = 0;
+       h_nxrec[unit] = INF;
+       ds = hcommand(dev, NOP);
+       if ((ds&MOL)==0 || (flag && (ds&WRL)))
+               u.u_error = ENXIO;
+       if (u.u_error==0)
+               h_openf[unit]++;
+}
+
+htclose(dev, flag)
+{
+       register int unit;
+
+       unit = minor(dev) & 03;
+       if (flag) {
+               hcommand(dev, WEOF);
+               hcommand(dev, WEOF);
+       }
+/*     hcommand(dev, REW);     */
+/* for 'mtm' file positioning */
+       if((minor(dev)&4) == 0) /* no 4 -> rewind */
+               hcommand(dev,REW) ;
+       else if(flag)  /* no rewind - backup over last EOF */
+               hcommand(dev&(~4),SREV) ;
+       h_openf[unit] = 0;
+}
+
+hcommand(dev, com)
+{
+       register struct buf *bp;
+
+       bp = &chtbuf;
+       spl5();
+       while(bp->b_flags&B_BUSY) {
+               bp->b_flags |= B_WANTED;
+               sleep(bp, PRIBIO);
+       }
+       spl0();
+       bp->b_dev = dev;
+       bp->b_resid = com;
+       bp->b_blkno = 0;
+       bp->b_flags = B_BUSY|B_READ;
+       htstrategy(bp);
+       iowait(bp);
+       if(bp->b_flags&B_WANTED)
+               wakeup(bp);
+       bp->b_flags = 0;
+       return(bp->b_resid);
+}
+
+htstrategy(bp)
+register struct buf *bp;
+{
+       register daddr_t *p;
+
+       if(bp != &chtbuf) {
+               p = &h_nxrec[minor(bp->b_dev)&03];
+               if(bp->b_blkno > *p) {
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = ENXIO;
+                       iodone(bp);
+                       return;
+               }
+               if(bp->b_blkno == *p && bp->b_flags&B_READ) {
+                       bp->b_resid = bp->b_bcount;
+                       clrbuf(bp);
+                       iodone(bp);
+                       return;
+               }
+               if ((bp->b_flags&B_READ)==0)
+                       *p = bp->b_blkno + 1;
+       }
+       bp->av_forw = NULL;
+       spl5();
+       if (httab.b_actf == NULL)
+               httab.b_actf = bp;
+       else
+               httab.b_actl->av_forw = bp;
+       httab.b_actl = bp;
+       if (httab.b_active==0)
+               htstart();
+       spl0();
+}
+
+htstart()
+{
+       register struct buf *bp;
+       register unit, den;
+       daddr_t blkno;
+
+    loop:
+       if ((bp = httab.b_actf) == NULL)
+               return;
+       unit = minor(bp->b_dev);
+       den = P800 | (unit&03);
+       if(unit >= 8)
+               den = P1600 | (unit&03);
+       if((HTADDR->httc&03777) != den)
+               HTADDR->httc = den;
+       unit &= 03;
+       blkno = h_blkno[unit];
+       if (bp == &chtbuf) {
+               if (bp->b_resid==NOP) {
+                       bp->b_resid = HTADDR->htds & 0xffff;
+                       goto next;
+               }
+               httab.b_active = SCOM;
+               HTADDR->htfc = 0;
+               HTADDR->htcs1 = bp->b_resid|GO;
+               return;
+       }
+       if (h_openf[unit] < 0 || bp->b_blkno > h_nxrec[unit])
+               goto abort;
+       if (blkno == bp->b_blkno) {
+               httab.b_active = SIO;
+               HTADDR->htfc = -bp->b_bcount;
+               mbastart(bp, HTADDR);
+       } else {
+               if (blkno < bp->b_blkno) {
+                       httab.b_active = SSFOR;
+                       HTADDR->htfc = blkno - bp->b_blkno;
+                       HTADDR->htcs1 = SFORW|GO;
+               } else {
+                       httab.b_active = SSREV;
+                       HTADDR->htfc = bp->b_blkno - blkno;
+                       HTADDR->htcs1 = SREV|GO;
+               }
+       }
+       return;
+
+    abort:
+       bp->b_flags |= B_ERROR;
+
+    next:
+       httab.b_actf = bp->av_forw;
+       iodone(bp);
+       goto loop;
+}
+
+htintr(mbastat, as)
+{
+       register struct buf *bp;
+       register int unit, state;
+       int     err;
+
+       if ((bp = httab.b_actf)==NULL)
+               return;
+       unit = minor(bp->b_dev) & 03;
+       state = httab.b_active;
+       httab.b_active = 0;
+       if (HTADDR->htds&(ERR|EOT|TM) || mbastat & MBAEBITS) {
+               err = HTADDR->hter & 0xffff;
+/*
+printf("ht2:mbas=%x, ds=%x, err=%x\n", mbastat, HTADDR->htds, err);
+*/
+               if ((mbastat & MBAEBITS) || (err&HARD))
+                       state = 0;
+               if (bp == &rhtbuf)
+                       err &= ~FCE;
+               if ((bp->b_flags&B_READ) && (HTADDR->htds&PES))
+                       err &= ~(CS|COR);
+               if(HTADDR->htds&EOT || (HTADDR->htds&MOL)==0) {
+                       if(h_openf[unit])
+                               h_openf[unit] = -1;
+               }
+               else if(HTADDR->htds&TM) {
+                       HTADDR->htfc = 0;
+                       h_nxrec[unit] = bp->b_blkno;
+                       state = SOK;
+               }
+               else if(state && err == 0)
+                       state = SOK;
+               if(httab.b_errcnt > 4) {
+                       deverror(bp, HTADDR->hter, mbastat);
+                       }
+               ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE;
+               HTADDR->htcs1 = DCLR|GO;
+               ((struct mba_regs *)MBA1)->mba_cr |= MBAIE;
+               if (state==SIO && ++httab.b_errcnt < 10) {
+                       httab.b_active = SRETRY;
+                       h_blkno[unit]++;
+                       HTADDR->htfc = -1;
+                       HTADDR->htcs1 = SREV|GO;
+                       return;
+               }
+               if (state!=SOK) {
+                       bp->b_flags |= B_ERROR;
+                       state = SIO;
+               }
+       } else if (HTADDR->htcs1 < 0) { /* SC */
+               if(HTADDR->htds & ERR) {
+                       ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE;
+                       HTADDR->htcs1 = DCLR|GO;
+                       ((struct mba_regs *)MBA1)->mba_cr |= MBAIE;
+               }
+       }
+       switch(state) {
+       case SIO:
+       case SOK:
+               h_blkno[unit]++;
+
+       case SCOM:
+               httab.b_errcnt = 0;
+               httab.b_actf = bp->av_forw;
+               bp->b_resid = - (HTADDR->htfc & 0xffff);
+               if (bp->b_flags & B_READ)
+                       bp->b_resid += bp->b_bcount;
+               iodone(bp);
+               break;
+
+       case SRETRY:
+               if((bp->b_flags&B_READ)==0) {
+                       httab.b_active = SSFOR;
+                       HTADDR->htcs1 = ERASE|GO;
+                       return;
+               }
+
+       case SSFOR:
+       case SSREV:
+               if(HTADDR->htds & TM) {
+                       if(state == SSREV) {
+                               h_nxrec[unit] = bp->b_blkno - (HTADDR->htfc&0xffff);
+                               h_blkno[unit] = h_nxrec[unit];
+                       } else {
+                               h_nxrec[unit] = bp->b_blkno + (HTADDR->htfc & 0xffff) - 1;
+                               h_blkno[unit] = bp->b_blkno + (HTADDR->htfc & 0xffff);
+                       }
+               } else
+                       h_blkno[unit] = bp->b_blkno;
+               break;
+
+       default:
+               return;
+       }
+       htstart();
+}
+
+htread(dev)
+{
+       htphys(dev);
+       physio(htstrategy, &rhtbuf, dev, B_READ);
+}
+
+htwrite(dev)
+{
+       htphys(dev);
+       physio(htstrategy, &rhtbuf, dev, B_WRITE);
+}
+
+htphys(dev)
+{
+       register unit;
+       daddr_t a;
+
+       unit = minor(dev) & 03;
+       if(unit < NUNIT) {
+               a = u.u_offset >> 9;
+               h_blkno[unit] = a;
+               h_nxrec[unit] = a+1;
+       }
+}
diff --git a/usr/src/slowsys/sys/iget.c b/usr/src/slowsys/sys/iget.c
new file mode 100644 (file)
index 0000000..c0337a1
--- /dev/null
@@ -0,0 +1,316 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mount.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/ino.h"
+#include "../h/filsys.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+/*
+ * Look up an inode by device,inumber.
+ * If it is in core (in the inode structure),
+ * honor the locking protocol.
+ * If it is not in core, read it in from the
+ * specified device.
+ * If the inode is mounted on, perform
+ * the indicated indirection.
+ * In all cases, a pointer to a locked
+ * inode structure is returned.
+ *
+ * printf warning: no inodes -- if the inode
+ *     structure is full
+ * panic: no imt -- if the mounted file
+ *     system is not in the mount table.
+ *     "cannot happen"
+ */
+struct inode *
+iget(dev, ino)
+dev_t dev;
+ino_t ino;
+{
+       register struct inode *ip;
+       register struct mount *mp;
+       register struct inode *oip;
+       register struct buf *bp;
+       register struct dinode *dp;
+
+loop:
+       oip = NULL;
+       for(ip = &inode[0]; ip < &inode[NINODE]; ip++) {
+               if(ino == ip->i_number && dev == ip->i_dev) {
+                       if((ip->i_flag&ILOCK) != 0) {
+                               ip->i_flag |= IWANT;
+                               sleep((caddr_t)ip, PINOD);
+                               goto loop;
+                       }
+                       if((ip->i_flag&IMOUNT) != 0) {
+                               for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+                               if(mp->m_inodp == ip) {
+                                       dev = mp->m_dev;
+                                       ino = ROOTINO;
+                                       goto loop;
+                               }
+                               panic("no imt");
+                       }
+                       ip->i_count++;
+                       ip->i_flag |= ILOCK;
+                       return(ip);
+               }
+               if(oip==NULL && ip->i_count==0)
+                       oip = ip;
+       }
+       ip = oip;
+       if(ip == NULL) {
+               printf("Inode table overflow\n");
+               u.u_error = ENFILE;
+               return(NULL);
+       }
+       ip->i_dev = dev;
+       ip->i_number = ino;
+       ip->i_flag = ILOCK;
+       ip->i_count++;
+       ip->i_un.i_lastr = 0;
+       bp = bread(dev, itod(ino));
+       /*
+        * Check I/O errors
+        */
+       if((bp->b_flags&B_ERROR) != 0) {
+               brelse(bp);
+               iput(ip);
+               return(NULL);
+       }
+       dp = bp->b_un.b_dino;
+       dp += itoo(ino);
+       iexpand(ip, dp);
+       brelse(bp);
+       return(ip);
+}
+
+iexpand(ip, dp)
+register struct inode *ip;
+register struct dinode *dp;
+{
+       register char *p1;
+       char *p2;
+       int i;
+
+       ip->i_mode = dp->di_mode;
+       ip->i_nlink = dp->di_nlink;
+       ip->i_uid = dp->di_uid;
+       ip->i_gid = dp->di_gid;
+       ip->i_size = dp->di_size;
+       p1 = (char *)ip->i_un.i_addr;
+       p2 = (char *)dp->di_addr;
+       for(i=0; i<NADDR; i++) {
+               *p1++ = *p2++;
+               *p1++ = *p2++;
+               *p1++ = *p2++;
+               *p1++ = 0;
+       }
+}
+
+/*
+ * Decrement reference count of
+ * an inode structure.
+ * On the last reference,
+ * write the inode out and if necessary,
+ * truncate and deallocate the file.
+ */
+iput(ip)
+register struct inode *ip;
+{
+
+       if(ip->i_count == 1) {
+               ip->i_flag |= ILOCK;
+               if(ip->i_nlink <= 0) {
+                       itrunc(ip);
+                       ip->i_mode = 0;
+                       ip->i_flag |= IUPD|ICHG;
+                       ifree(ip->i_dev, ip->i_number);
+               }
+               iupdat(ip, &time, &time);
+               prele(ip);
+               ip->i_flag = 0;
+               ip->i_number = 0;
+       }
+       ip->i_count--;
+       prele(ip);
+}
+
+/*
+ * Check accessed and update flags on
+ * an inode structure.
+ * If either is on, update the inode
+ * with the current time.
+ */
+iupdat(ip, ta, tm)
+register struct inode *ip;
+time_t *ta, *tm;
+{
+       register struct buf *bp;
+       struct dinode *dp;
+       register char *p1;
+       char *p2;
+       int i;
+
+       if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
+               if(getfs(ip->i_dev)->s_ronly)
+                       return;
+               bp = bread(ip->i_dev, itod(ip->i_number));
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       return;
+               }
+               dp = bp->b_un.b_dino;
+               dp += itoo(ip->i_number);
+               dp->di_mode = ip->i_mode;
+               dp->di_nlink = ip->i_nlink;
+               dp->di_uid = ip->i_uid;
+               dp->di_gid = ip->i_gid;
+               dp->di_size = ip->i_size;
+               p1 = (char *)dp->di_addr;
+               p2 = (char *)ip->i_un.i_addr;
+               for(i=0; i<NADDR; i++) {
+                       *p1++ = *p2++;
+                       *p1++ = *p2++;
+                       *p1++ = *p2++;
+                       if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
+                          && (ip->i_mode&IFMT)!=IFMPB)
+                               printf("iaddress > 2^24\n");
+               }
+               if(ip->i_flag&IACC)
+                       dp->di_atime = *ta;
+               if(ip->i_flag&IUPD)
+                       dp->di_mtime = *tm;
+               if(ip->i_flag&ICHG)
+                       dp->di_ctime = time;
+               ip->i_flag &= ~(IUPD|IACC|ICHG);
+               bdwrite(bp);
+       }
+}
+
+/*
+ * Free all the disk blocks associated
+ * with the specified inode structure.
+ * The blocks of the file are removed
+ * in reverse order. This FILO
+ * algorithm will tend to maintain
+ * a contiguous free list much longer
+ * than FIFO.
+ */
+itrunc(ip)
+register struct inode *ip;
+{
+       register i;
+       dev_t dev;
+       daddr_t bn;
+
+       i = ip->i_mode & IFMT;
+       if (i!=IFREG && i!=IFDIR)
+               return;
+       dev = ip->i_dev;
+       for(i=NADDR-1; i>=0; i--) {
+               bn = ip->i_un.i_addr[i];
+               if(bn == (daddr_t)0)
+                       continue;
+               ip->i_un.i_addr[i] = (daddr_t)0;
+               switch(i) {
+
+               default:
+                       free(dev, bn);
+                       break;
+
+               case NADDR-3:
+                       tloop(dev, bn, 0, 0);
+                       break;
+
+               case NADDR-2:
+                       tloop(dev, bn, 1, 0);
+                       break;
+
+               case NADDR-1:
+                       tloop(dev, bn, 1, 1);
+               }
+       }
+       ip->i_size = 0;
+       ip->i_flag |= ICHG|IUPD;
+}
+
+tloop(dev, bn, f1, f2)
+dev_t dev;
+daddr_t bn;
+{
+       register i;
+       register struct buf *bp;
+       register daddr_t *bap;
+       daddr_t nb;
+
+       bp = NULL;
+       for(i=NINDIR-1; i>=0; i--) {
+               if(bp == NULL) {
+                       bp = bread(dev, bn);
+                       if (bp->b_flags & B_ERROR) {
+                               brelse(bp);
+                               return;
+                       }
+                       bap = bp->b_un.b_daddr;
+               }
+               nb = bap[i];
+               if(nb == (daddr_t)0)
+                       continue;
+               if(f1) {
+                       brelse(bp);
+                       bp = NULL;
+                       tloop(dev, nb, f2, 0);
+               } else
+                       free(dev, nb);
+       }
+       if(bp != NULL)
+               brelse(bp);
+       free(dev, bn);
+}
+
+/*
+ * Make a new file.
+ */
+struct inode *
+maknode(mode)
+{
+       register struct inode *ip;
+
+       ip = ialloc(u.u_pdir->i_dev);
+       if(ip == NULL) {
+               iput(u.u_pdir);
+               return(NULL);
+       }
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if((mode&IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode & ~u.u_cmask;
+       ip->i_nlink = 1;
+       ip->i_uid = u.u_uid;
+       ip->i_gid = u.u_gid;
+       wdir(ip);
+       return(ip);
+}
+
+/*
+ * Write a directory entry with
+ * parameters left as side effects
+ * to a call to namei.
+ */
+wdir(ip)
+struct inode *ip;
+{
+
+       u.u_dent.d_ino = ip->i_number;
+       bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
+       u.u_count = sizeof(struct direct);
+       u.u_segflg = 1;
+       u.u_base = (caddr_t)&u.u_dent;
+       writei(u.u_pdir);
+       iput(u.u_pdir);
+}
diff --git a/usr/src/slowsys/sys/locore.s b/usr/src/slowsys/sys/locore.s
new file mode 100644 (file)
index 0000000..2a1a698
--- /dev/null
@@ -0,0 +1,1185 @@
+       .set    HIGH,31         # mask for total disable
+       .set    SZPT,4          # number of pages of user page table allocated per user
+       .set    MCKVEC,4        # offset into Scbbase of machine check vector
+
+# Trap vectors and C interface for Vax
+
+#
+#
+#
+# System control block
+#
+
+       .set    INTSTK,1        # handle this interrupt on the interrupt stack
+       .set    HALT,3          # halt if this interrupt occurs
+       .align  9
+       .globl  Scbbase
+Scbbase:
+       .long   Xrandom + HALT  # unused
+       .long   Xmachcheck + HALT       # machine check interrupt
+       .long   Xkspnotval + HALT       # kernal stack not valid
+       .long   Xpowfail + HALT # power fail
+       .long   Xprivinflt      # privileged instruction 
+       .long   Xxfcflt         # xfc instruction 
+       .long   Xresopflt       # reserved operand 
+       .long   Xresadflt       # reserved addressing 
+       .long   Xprotflt        # protection 
+       .long   Xsegflt         # segmentation 
+       .long   Xtracep         # trace pending
+       .long   Xbptflt         # bpt instruction
+       .long   Xrandom + HALT  # compatibility mode fault
+       .long   Xarithtrap      # arithmetic trap
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xsyscall        # chmk
+       .long   Xchme+HALT              # chme
+       .long   Xchms+HALT              # chms
+       .long   Xchmu+HALT              # chmu
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # software level 1
+       .long   Xrandom + HALT  # software level 2 (asts)
+       .long   Xresched        # reschedule nudge
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+ubabase:
+       .long   Xclockint + INTSTK      # clock
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xconsrint + INTSTK      # console receiver 
+       .long   Xconsxint + INTSTK      # console transmitter
+
+#      I/O vectors
+
+# IPL 14
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xua0int + INTSTK        # UBA 0 br4
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+
+# IPL 15
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xua0int + INTSTK        # UBA 0 br5
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xmba0int + INTSTK       # mass bus adapter 0
+       .long   Xmba1int + INTSTK       # mass bus adapter 1
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+
+# IPL 16
+       .long   Xrandom + HALT          # unused
+       .long   Xrandom + HALT          # unused
+       .long   Xrandom + HALT          # unused
+       .long   Xua0int + INTSTK        # UBA 0 br6
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+
+# IPL 17
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+       .long   Xrandom + HALT  # unused
+
+
+#  0x200
+# Produce a core image dump on mag tape
+       .globl  doadump
+doadump:
+       movl    sp,dumpstack    # save stack pointer
+       movab   dumpstack,sp    # reinit sp 
+       mfpr    $PCBB,-(sp)             # save u-area pointer
+       mfpr    $MAPEN,-(sp)    # save value
+       mfpr    $IPL,-(sp)              # ...
+       mtpr    $0,$MAPEN               # turn off memory mapping
+       mtpr    $HIGH,$IPL              # disable interrupts
+       pushr   $0x3fff                 # save regs 0 - 13
+       calls   $0,_dump        # produce dump
+       halt
+
+       .data
+       .align  2
+       .space  58*4            # seperate stack for tape dumps
+       .globl  dumpstack
+dumpstack: 
+       .space  4
+       .text
+
+
+# I/O interrupt vector routines
+#
+
+# Catch random or unexpected interrupts
+
+       .align  2
+Xrandom:
+Xmachcheck:
+Xkspnotval:
+Xpowfail:
+Xchme:
+Xchms:
+Xchmu:
+       halt
+
+# Massbus 0 adapter interrupts
+
+       .align  2
+Xmba0int:
+       pushr   $0x3f           # save r0 - r5
+       movab   MBA0_CSR,r0     # point at mba regs
+       movl    MBA_AS(r0),r1           # get attn summary bits
+       cvtwl   r1,-(sp)                # push attn summary as arg
+       pushl   MBA_SR(r0)      # pass sr as argument
+       mnegl   $1,MBA_SR(r0)   # clear attention bit
+       calls   $2,_hpintr      # call rp06 interrupt dispatcher
+       brw     int_ret         # merge with common interrupt code
+
+
+# Massbus 1 adapter interrupts
+
+       .align  2
+Xmba1int:
+       pushr   $0x3f
+       movab   MBA1_CSR,r0
+       pushl   MBA_AS(r0)
+       mnegl   $1,MBA_AS(r0)
+       pushl   MBA_SR(r0)              # pass cr as argument_
+       mnegl   $1,MBA_SR(r0)   # clear attention bit
+       calls   $2,_htintr      # call te16 interrupt dispatcher
+       brw     int_ret         # return from interrupt
+
+
+# Unibus adapter interrupts
+
+       .align  2
+Xua0int:       #  UBA 0 interrupts
+       pushr   $0x3f  #  save regs 0-5
+       pushab  UBA0  # save UBA base addr
+       brb     Xuacom  #  jump to common code
+Xua1int :      #  UBA 1 interrupts
+Xuacom :       #  common code for UBA interrupts
+       popr    $1              # UBA base addr
+       mfpr    $IPL,r2         # get br level
+       movl    UBR_OFF-20*4(r0)[r2],r3 # get unibus device vector
+       bleq    ubasrv  # branch if zero vector or UBA service required
+#  normal UBA interrupt point - device on a UBA has generated an
+#    interrupt - r3 holds interrupt vector
+ubanorm :
+       movl    _UNIvec(r3),r1  #  get interrupt service routine address
+#                      and controller code from UNIBUS vector area
+       extzv   $27,$4,r1,-(sp)  #  controller code is in 4 most
+#                              significant bits-1 of ISR addr
+       bicl2   $0x78000000,r1  #  clear code
+       calls   $1,(r1)  #  call ISR
+       brw     int_ret  #  go to common interrupt return
+#  here for zero or negative UBA interrupt vector.
+#  negative vector -> UBA requires service
+ubasrv :
+       beql    ubapass
+#
+#  UBA service required
+#  The following 'printf' calls should probably be replaced
+#    with calls to an error logger and/or some corrective action.
+       bitl    $CFGFLT,UCN_OFF(r0)  #  any SBI faults ?
+       beql    UBAflt
+       pushab  SBImsg
+       calls   $1,_printf
+       halt
+#
+#  no SBI fault bits set in UBA config reg - must be
+#    some error bits set in UBA status reg
+UBAflt :
+       movl    UST_OFF(r0),r2  #  UBA status reg
+       pushr   r2
+       pushab  UBAmsg
+       calls   $2,_printf
+       movl    r2,UST_OFF(r0)  #  clear error bits
+       bicl2   $0x80000000,r1  #  clear neg bit in vector
+       bneq    ubanorm  #  branch if normal UBA interrupt to process
+       brb     int_ret         # restore regs and return
+#
+#  zero interrupt vector - print message & continue
+ubapass :
+       pushab  ZERmsg
+       calls   $1,_printf
+       brb     int_ret
+
+
+# Console receiver interrupt
+
+       .align  2
+Xconsrint:
+       pushr   $0x3f           # save registers 0 - 5
+       calls   $0,_consrint
+       brb     int_ret         # merge
+
+
+# Console transmit interrupt
+       .align  2
+Xconsxint:
+       pushr   $0x3f           # save registers 0 - 5
+       calls   $0,_consxint
+       brb     int_ret
+
+
+# Clock interrupt
+       .align  2
+Xclockint:
+       pushr   $0x3f           # save regs 0 - 5
+       pushl   4+6*4(sp)       # push psl
+       pushl   4+6*4(sp)       # push pc
+       calls   $2,_clock
+       brb     int_ret
+
+
+#
+# Common code for interrupts
+# At this point, the interrupt stack looks like:
+#
+#               ___________
+#              |    r0     | :isp
+#              |-----------|
+#              |    ...    |
+#              |-----------|
+#              |    r13    |
+#              |-----------|
+#              |    pc     |
+#              |-----------|
+#              |    psl    |
+#              |___________|
+
+
+int_ret:
+       bbssi   $0,idleflag,int_r0              # set idle escape flag (no wait instr)
+int_r0:
+       popr    $0x3f           # restore regs 0 - 5
+       bitl    $PSL_CURMOD,4(sp)       # interrupt from user mode?
+       beql    int_r1          # no, from kernal, just rei
+       tstb    _runrun         # should we reschedule?
+       beql    int_r1          # no, just rei
+#
+# If here, interrupt from user mode, and time to reschedule.
+#      to do this, we set a software level 3 interrupt to
+#      change to kernal mode, switch stacks,
+#      and format kernal stack for a `qswitch' trap to force
+#      a reschedule.
+#
+       mtpr    $3,$SIRR        # request level 1 software interrupt
+int_r1:
+       rei                     # return to interrupted process
+
+#
+# Trap and fault vector routines
+#
+
+#      Reschedule trap (Software level 3 interrupt)
+       .align  2
+Xresched:
+       movpsl  -(sp)   # get ps
+       bicl2   $PSL_IPL,(sp)   # lower ipl
+       pushab  resc1           # push pc
+       rei                     # lower ipl, jump to resc1
+
+resc1:
+       pushl   $0                      # dummy code
+       pushl   $RESCHED        # type
+       brb     alltraps        # merge
+
+
+#      privileged instruction fault
+       .align  2
+Xprivinflt:
+       pushl   $0              # push dummy code
+       pushl   $PRIVINFLT      # push type
+       brb     alltraps        # merge
+
+
+
+#      xfc instruction fault
+       .align  2
+Xxfcflt:
+       pushl   $0              # push dummy code value
+       pushl   $XFCFLT         # push type value
+       brb     alltraps        # merge
+
+
+#      reserved operand fault
+       .align  2
+Xresopflt:
+       pushl   $0              # push dummy code value
+       pushl   $RESOPFLT       # push type value
+       brb     alltraps        # merge
+
+
+#      reserved addressing mode fault
+       .align  2
+Xresadflt:
+       pushl   $0              # push dummy code value
+       pushl   $RESADFLT       # push type value
+       brb     alltraps        # merge with common code
+
+
+#      bpt instruction fault
+       .align  2
+Xbptflt:
+       pushl   $0              # push dummy code value
+       pushl   $BPTFLT         # push type value
+       brb     alltraps        # merge with common code
+
+#      Trace trap
+
+       .align  2
+Xtracep:
+       pushl   $0              # push dummy code value
+       pushl   $TRCTRAP        # push type value
+       brb     alltraps        # go do it
+
+#      Arithmitic trap
+       .align  2
+Xarithtrap:
+       pushl   $ARITHTRAP      # push type value
+       brb     alltraps        # merge with common code
+
+
+#      Protection  fault
+
+       .align  2
+Xprotflt:
+       blbs    (sp),Xsegflt            # check for pt length violation
+       addl2   $4,sp           # pop fault param word 
+       pushl   $PROTFLT
+       brb     alltraps
+
+#      Segmentation fault
+
+       .align  2
+Xsegflt:
+       addl2   $4,sp
+       pushl   $SEGFLT
+       brb     alltraps
+
+
+
+
+#
+# CHMK trap (syscall trap)
+#      on entry, kernal stack:
+#
+#               ___________ 
+#              |    code   | :ksp
+#              |-----------|
+#              |    pc     |
+#              |-----------|
+#              |    psl    |
+#              |___________|
+#
+#
+#
+#      stack (parameters) at calls to _trap:
+#
+#               ___________ 
+#              |    ap     | :ksp
+#              |-----------|
+#              |    r0     |
+#              |-----------|
+#              |    ...    |
+#              |-----------|
+#              |    r13    |
+#              |-----------|
+#              |    usp    |
+#              |-----------|
+#              |    type   |
+#              |-----------|
+#              |    code   |
+#              |-----------|
+#              |    pc     |
+#              |-----------|
+#              |    psl    |
+#              |___________|
+#
+
+       .align  2
+Xsyscall:
+       pushl   $SYSCALL        # push type value
+alltraps:
+       movq    8(sp),_u+PCB_PC # save pc
+       bitl    $PSL_CURMOD,12(sp)      # from user mode?
+       beql    sysc1           # no
+# Prepare arguments to _trap, note that type has already been pushed
+       mfpr    $USP,-(sp)      # get usp
+       pushr   $0x3fff         # registers 0 - 13
+       pushl   ap              # ptr to syscall parameters
+#
+# Call _trap with wrong number of arguments
+#   so args not popped by ret
+#
+       calls   $1,_trap
+# Restore
+       popr    $0x3fff         # restore regs 0 - 13
+       mtpr    (sp)+,$USP      # restore usp
+       addl2   $8,sp           # pop type, code
+#
+       bitl    $PSL_CURMOD,4(sp)               # are we returning to user mode?
+       beql    sysc2           # no
+# Return
+       rei
+
+sysc1:
+       movab   emsg1,eptr      # set message pointer
+       brb     err_print       # print message and halt
+
+sysc2:
+       movab   emsg2,eptr      # pointer to error message
+       brb     err_print       # print msg and halt
+
+#
+# err_print
+#      print message on console and die
+#      message pointed to by eptr, terminated by zero byte.
+#
+
+err_print:
+       mtpr    $HIGH,$IPL      # disable all interrupts
+       mtpr    $0,$TXCS        # disable interrupts on console transmitter
+eloop1:
+       mfpr    $TXCS,ewk1      # get transmitter status
+       bbc     $TXCS_BRDY,ewk1,eloop1  # loop if not ready to transmit
+       tstb    *eptr           # end of message?
+       beql    eout            # yes, out of loop
+       movzbl  *eptr,ewk1      # get byte of message
+       incl    eptr            # bump pointer
+       mtpr    ewk1,$TXDB      # give byte to transmitter
+       brb     eloop1          # loop
+
+eout:
+       halt
+
+       .data
+eptr:  .long   0
+ewk1:  .long   0
+       .text
+
+
+
+#
+# Initialization
+
+#
+#      IPL == 1F
+#      MAPEN == off
+#      SCBB, PCBB not set
+#      SBR, SLR not set
+#      ISP, KSP not set
+#
+       .globl  start
+start:
+       .word   0x0000
+       mtpr    $HIGH,$IPL              # no interrupts yet
+       mtpr    $Scbbase,$SCBB  # set SCBB
+       mtpr    $_Sysmap,$SBR   # set SBR
+       mtpr    $Syssize,$SLR   # set SLR
+       mtpr    $_Sysmap,$P0BR  # set temp P0BR
+       mtpr    $Syssize,$P0LR  # set temp P0LR
+       movl    $_intstack+2048,sp      # set ISP
+# initialize i/o adatpers
+       movl    $1,PHYSMBA0+4   # init & interrupt enable
+       movl    $4,PHYSMBA0+4   # init & interrupt enable
+       movl    $1,PHYSMBA1+4   # init  interrupt enable
+       movl    $4,PHYSMBA1+4   # init  interrupt enable
+       movl    $1,PHYSUBA+4    # init  interrupt enable
+       movl    $0x78,PHYSUBA+4 # init  interrupt enable
+
+       movl    Scbbase+MCKVEC,r5       # save machine check entry
+       movab   startint+INTSTK,Scbbase+MCKVEC  # set new vector address
+#
+# will now see how much memory there really is
+#      in 64kb chunks, save number of bytes in r7
+#
+       mtpr    $HIGH-1,$IPL    # allow machine check interrupts
+       clrl    r7
+startlp:
+       tstl    (r7)            # this chunk really there?
+       acbl    $8096*1024-1,$64*1024,r7,startlp        # loop till machine check
+       brb     startint        # full load of memory, avoid .align
+       .align  2
+startint:
+       mtpr    $0,$SBIFS               # clear sbi fault status
+       movl    r5,Scbbase+MCKVEC       # restore machine check vector
+       movl    $_intstack+2048,sp      # reset interrupt stack pointer
+
+#      clear memory starting with unitialized data (kernal)
+       movab   _edata,r6
+       movab   _end+8096,r5    # clear uninitialized data and some slop
+strtclr:
+       clrq    (r6)
+       acbl    r5,$8,r6,strtclr
+
+#
+#      initialize system page table
+#
+       movab   _etext+511,r1   # end of kernal text segment
+       bbcc    $31,r1,strt1    # turn off high order bit
+strt1:
+       ashl    $-9,r1,r1       # last page of kernal text
+       clrl    r2              # point at first kernal text page
+strtlp1:
+       bisl3   $PG_V|PG_KR,r2,_Sysmap[r2]      # initialize page table entry
+       aoblss  r1,r2,strtlp1   # fill text entries
+       movab   _end+511,r1     # end of kernal data segment
+       bbcc    $31,r1,strt2    # turn off high order bit
+strt2:
+       ashl    $-9,r1,r1       # last page of kernal data
+strtlp2:
+       bisl3   $PG_V|PG_KW,r2,_Sysmap[r2]      # fill data entries
+       aoblss  r1,r2,strtlp2
+
+#      init i/o space page table entries
+       movl    $PHYSUBA/512,r1         # page frame number for uba
+       movab   _Sysmap+uba_offset,r2   # page table address
+       movab   15(r1),r3       # last pt entry
+strtlp3:
+       bisl3   $PG_V|PG_KW,r1,(r2)+    # init pt entry
+       aobleq  r3,r1,strtlp3
+       movl    $PHYSUMEM/512,r1
+       movab   _Sysmap+umem_offset,r2  # page table address
+       movab   15(r1),r3               # limit
+strtlp4:
+       bisl3   $PG_V|PG_KW,r1,(r2)+
+       aobleq  r3,r1,strtlp4
+       movl    $PHYSMBA0/512,r1
+       movab   _Sysmap+mba0_offset,r2
+       movab   15(r1),r3
+strtlp5:
+       bisl3   $PG_V|PG_KW,r1,(r2)+
+       aobleq  r3,r1,strtlp5
+       movl    $PHYSMBA1/512,r1
+       movab   _Sysmap+mba1_offset,r2
+       movab   15(r1),r3
+strtlp6:
+       bisl3   $PG_V|PG_KW,r1,(r2)+
+       aobleq  r3,r1,strtlp6
+
+       mtpr    $1,$TBIA        # invalidate all trans buffer entries
+       mtpr    $1,$MAPEN       # turn on memory mapping
+       jmp     *$startmap      # put system virtual address in pc
+
+startmap:
+# set maxmem = btoc(r7)
+       ashl    $-9,r7,_maxmem
+
+#
+# Setup context for proc[0] == Scheduler
+#
+# address first page past _end
+#      this will be u area for proc[0].
+#      initialize u area page table entries.
+#      initialize (slightly) the pcb.
+
+       movab   _end+511,r6
+       bicl2   $0x1ff,r6       # make page boundary
+
+# set up u area page table
+       bbcc    $31,r6,strt3
+strt3:
+       ashl    $-9,r6,r3               # r3 = btoc(r6)
+       bisl3   $PG_V|PG_KW,r3,_Sysmap+u_ptoffset       # init first u pt entry
+       movab   _u,r1           # point at _u area
+       mtpr    r1,$TBIS
+       movab   usize*512(r1),PCB_KSP(r1)       # init ksp
+       mnegl   $1,PCB_ESP(r1)          # invalidate esp
+       mnegl   $1,PCB_SSP(r1)          # invalidate ssp
+       movl    $0x80000000,PCB_USP(r1)         # set user sp
+       movab   _u+usize*512,PCB_P0BR(r1)       # p0 page table pointer
+       clrl    PCB_P0LR(r1)            # size zero page table
+       movb    $4,PCB_P0LR+3(r1)       # disable ast
+       movab   _u+(usize+SZPT)*512-0x800000,PCB_P1BR(r1)               # p1 page table pointer
+       movl    $0x200000,PCB_P1LR(r1)          # invalid p1 p t length
+       movl    $SZPT,PCB_SZPT(r1)              # init number pages usr page table
+       ashl    $-9,r6,-(sp)    # push arg for setupu
+       pushl   $1              # ditto
+       movl    sp,ap   # set up arg pointer
+       bsbw    setupu
+       addl2   $8,sp           # pop stack
+
+       mtpr    r6,$PCBB                # first pcb
+
+       ldpctx                  # set regs, p0br, p0lr, p1br, p1lr, 
+#                              astlvl, ksp, and change to kernal mode
+       addl2   $8,sp           # pop dummy pc, psl
+       mtpr    $0,$IPL         # enable interrupts
+       movab   _end+511,r0     # calculate firstaddr
+       bbcc    $31,r0,strt4
+strt4:
+       ashl    $-9,r0,-(sp)    # convert to clicks and stack
+       calls   $1,_main        # startup, fork off /etc/init
+#
+# proc[1] == /etc/init now running here.
+# execute code at location 0, in user mode.
+#
+       pushl   $PSL_CURMOD|PSL_PRVMOD  # psl, user mode, ipl= 0
+       pushl   $0              # pc, $location 0
+       rei                     # do /etc/init
+
+
+#
+# Primitives
+#
+
+_display:      .globl  _display
+_savfp:        .globl  _savfp
+_restfp:       .globl  _restfp
+       .word   0x0000
+       ret
+
+_addupc:       .globl  _addupc
+       .word   0x0000
+       movl    8(ap),r2        # &u.u_prof
+       subl3   8(r2),4(ap),r0  # corrected pc
+       blss    addret
+       extzv   $1,$31,r0,r0    # logical right shift
+       extzv   $1,$31,12(r2),r1        # ditto for scale
+       mull2   r1,r0
+       ashl    $-14,r0,r0
+       incl    r0
+       bicb2   $1,r0
+       cmpl    r0,4(r2)        # length
+       bgequ   addret
+       addl2   (r2),r0         # base
+       probew  $3,$2,(r0)
+       beql    adderr
+       addw2   12(ap),(r0)
+addret:
+       ret
+adderr:
+       clrl    12(r2)
+       ret
+
+
+_fubyte:       .globl  _fubyte
+_fuibyte:.globl        _fuibyte
+       .word   0x0000
+       prober  $3,$1,*4(ap)    # byte accessible ?
+       beql    eret                    # no
+       movzbl  *4(ap),r0
+       ret
+
+_subyte:       .globl  _subyte
+_suibyte:.globl        _suibyte
+       .word   0x0000
+       probew  $3,$1,*4(ap)    # byte accessible ?
+       beql    eret                    # no
+       movb    8(ap),*4(ap)
+       clrl    r0
+       ret
+
+_fuword:       .globl  _fuword
+_fuiword:.globl        _fuiword
+       .word   0x0000
+       prober  $3,$4,*4(ap)
+       beql    eret
+       movl    *4(ap),r0
+       ret
+
+_suword:       .globl  _suword
+_suiword:.globl        _suiword
+       .word   0x0000
+       probew  $3,$4,*4(ap)
+       beql    eret
+       movl    8(ap),*4(ap)
+       clrl    r0
+       ret
+eret:
+       mnegl   $1,r0                   # error return
+       ret
+
+_copyin:       .globl  _copyin
+_copyiin:.globl        _copyiin
+       .word   0x0000
+       movl    12(ap),r0       # copy length
+       movl    4(ap),r1        # copy user address
+       cmpl    $512,r0         # probing one page or less ?
+       bgeq    cishort         # yes
+ciloop:
+       prober  $3,$512,(r1)    # bytes accessible ?
+       beql    eret            # no
+       addl2   $512,r1         # incr user address ptr
+       acbl    $513,$-512,r0,ciloop    # reduce count and loop
+cishort:
+       prober  $3,r0,(r1)      # bytes accessible ?
+       beql    eret            # no
+       movc3   12(ap),*4(ap),*8(ap)
+       clrl    r0
+       ret
+
+_copyout: .globl       _copyout
+_copyiout:.globl       _copyiout
+       .word   0x0000
+       movl    12(ap),r0       # get count
+       movl    8(ap),r1        # get user address
+       cmpl    $512,r0         # can do in one probew?
+       bgeq    coshort         # yes
+coloop:
+       probew  $3,$512,(r1)    # bytes accessible?
+       beql    eret            # no 
+       addl2   $512,r1         # increment user address
+       acbl    $513,$-512,r0,coloop    # reduce count and loop
+coshort:
+       probew  $3,r0,(r1)      # bytes accessible?
+       beql    eret            # no
+       movc3   12(ap),*4(ap),*8(ap)
+       clrl    r0
+       ret
+
+_idle: .globl  _idle
+       .word   0x0000
+       mtpr    $0,$IPL         # enable interrupts
+waitloc:       blbc    idleflag,waitloc        # loop until interrupt
+ewaitloc:      bbcci   $0,idleflag,idle1       # clear idle escape flag
+idle1:
+       ret
+       .data
+       .globl  _waitloc
+       .globl  _ewaitloc
+       .align  2
+_waitloc:      .long   waitloc
+_ewaitloc:     .long   ewaitloc
+idleflag:      .long   0
+       .text
+
+
+# save reg's and ret loc into save area - return 0
+       .globl  _save
+_save :                # save(save_area)
+       .word   0x0
+       mtpr    $HIGH,$IPL
+       movl    4(ap),r0  #  save area addr
+       movab   2*4(ap),sp  #  restore stack to val before 'save' call
+       movl    8(fp),ap  #  restore ap "       "       "
+       movl    16(fp),r1  #  restore pc        "       "       "
+       movl    12(fp),fp  #  restore fp        "       "       "
+       movq    r6,(r0)+
+       movq    r8,(r0)+
+       movq    r10,(r0)+
+       movq    ap,(r0)+  #  ap & fp
+       movl    sp,(r0)+
+       movl    r1,(r0)+  #  ret loc of call to 'save'
+       movpsl  -(sp)
+       pushl   r1
+       svpctx  # save reg's -> PCB
+       movpsl  -(sp)  # set up for return
+       bicl2   $PSL_IS|PSL_IPL,(sp)  #  undo SVPCTX
+       pushl   r1  #  ret loc
+       clrl    r0  #  return val
+       rei
+#
+#
+#  switch to another process's '_u' area - return val 1
+       .globl  _resume
+_resume :              #  resume(proc_addr,save_addr)
+       .word   0x0
+       mtpr    $HIGH,$IPL  # inhibit interrupts
+       ashl    $9,4(ap),r5  # proc byte addr
+                       #   area of proc argument
+       movl    8(ap),retloc
+       bsbw    setupu  #  set up '_sysmap' PTE's to map into '_u'
+       movl    _u,sp           # KSP from u-area
+       mtpr    r5,$PCBB
+       ldpctx
+       addl2   $8,sp           # clear ps,pc from stack
+       movl    retloc,r1  #  'ssav' or 'qsav' addr
+       movq    (r1)+,r6
+       movq    (r1)+,r8
+       movq    (r1)+,r10
+       movq    (r1)+,ap
+       movl    (r1)+,sp
+       movl    $1,r0  # return val
+       mtpr    $0,$IPL
+       jmp     *(r1)+  #  return to caller at 'save' address
+#
+       .data
+       .align  2
+retloc:        .space  1*4
+       .text
+
+
+# initialize u area page table entries
+
+setupu:
+       movl    (sp)+,r0                # get return pc
+       addl3   $PG_V|PG_KW,4(ap),r1    # first pt entry of user area
+       movab   usize(r1),r2    # one past last pt entry of user
+       movab   _Sysmap+u_ptoffset,r3   # addr for 1st user pt entry
+       movab   _u,r4
+       mtpr    r4,$TBIS        # invalidate old trans buffer entry
+       movl    r1,(r3)+        # store page table entry
+       addl2   _u+PCB_SZPT,r2  # add on size of user page table
+       brb     setulp1
+setulp:
+       mtpr    r4,$TBIS        # ivalidate page table entry
+       movl    r1,(r3)+        # store page table entry
+setulp1:
+       addl2   $512,r4
+       aoblss  r2,r1,setulp    # -> till done
+       jmp     (r0)            # funny return in case of changing stacks
+
+
+# disable interrupts
+_spl1: .globl  _spl1
+       .word   0x0000
+       mfpr    $IPL,r0         # get IPL value
+       mtpr    $2,$IPL         # disable RESCHED & AST interrupts
+       ret
+
+_spl4: .globl  _spl4
+       .word   0x0000
+       mfpr    $IPL,r0
+       mtpr    $0x14,$IPL              # disable bus level 4 interrupts
+       ret
+
+_spl5: .globl  _spl5
+       .word   0x0000
+       mfpr    $IPL,r0
+       mtpr    $0x15,$IPL              # disable bus level 5 interrupts
+       ret
+
+_spl6: .globl  _spl6
+_spl7: .globl  _spl7
+       .word   0x0000
+       mfpr    $IPL,r0
+       mtpr    $0x18,$IPL              # disable bus level 7 and clock interrupts
+       ret
+
+# enable interrupts
+_spl0: .globl  _spl0
+       .word   0x0000
+       mfpr    $IPL,r0
+       mtpr    $0,$IPL
+       ret
+
+# restore interrupt state
+_splx: .globl  _splx
+       .word   0x0000
+       mfpr    $IPL,r0
+       mtpr    4(ap),$IPL
+       ret
+
+#
+# Copy 1 relocation unit (512 bytes)
+# from one physical address to another
+_copyseg: .globl       _copyseg
+       .word   0x0000
+       mfpr    $IPL,r0         # get current pri level
+       mtpr    $HIGH,$IPL      # turn off interrupts
+       bisl3   $PG_V|PG_KR,4(ap),_Sysmap+CMAP1
+       bisl3   $PG_V|PG_KW,8(ap),_Sysmap+CMAP2
+       mtpr    $CADDR1,$TBIS   # invalidate entry for copy 
+       mtpr    $CADDR2,$TBIS
+       movc3   $512,CADDR1,CADDR2
+       mtpr    r0,$IPL # restore pri level
+       ret
+
+# zero out physical memory
+# specified in relocation units (512 bytes)
+_clearseg: .globl      _clearseg
+       .word   0x0000
+       mfpr    $IPL,r0         # get current pri level
+       mtpr    $HIGH,$IPL      # extreme pri level
+       bisl3   $PG_V|PG_KW,4(ap),_Sysmap+CMAP1
+       mtpr    $CADDR1,$TBIS
+       movc5   $0,(r0),$0,$512,CADDR1
+       mtpr    r0,$IPL         # restore pri level
+       ret
+
+# Check address
+# given virtual address, byte count, and rw flag
+#  returns 0 on no access
+_useracc:      .globl  _useracc
+       .word   0x0000
+       movl    4(ap),r0                # get va
+       movl    8(ap),r1                # count
+       tstl    12(ap)          # test for read access ?
+       bneq    userar  # yes
+       cmpl    $512,r1 # can we do it in one probe ?
+       bgeq    uaw2            # yes
+uaw1:
+       probew  $3,$512,(r0)
+       beql    uaerr           # no access
+       addl2   $512,r0
+       acbl    $513,$-512,r1,uaw1
+uaw2:
+       probew  $3,r1,(r0)
+       beql    uaerr
+       movl    $1,r0
+       ret
+
+userar:
+       cmpl    $512,r1
+       bgeq    uar2
+uar1:
+       prober  $3,$512,(r0)
+       beql    uaerr
+       addl2   $512,r0
+       acbl    $513,$-512,r1,uar1
+uar2:
+       prober  $3,r1,(r0)
+       beql    uaerr
+       movl    $1,r0
+       ret
+
+uaerr:
+       clrl    r0
+       ret
+
+#      kernacc
+#              check for kernal access privileges
+#
+
+       .globl  _kernacc
+_kernacc:
+       .word   0x0000
+
+       movl    4(ap),r0        # virtual address
+       bbcc    $31,r0,kacc1
+       mfpr    $SBR,r2 # address and length of page table (system)
+       mfpr    $SLR,r3
+       brb     kacc2
+kacc1:
+       bbsc    $30,r0,kacc3
+       mfpr    $P0BR,r2        # user P0
+       mfpr    $P0LR,r3
+       brb     kacc2
+kacc3:
+       mfpr    $P1BR,r2        # user P1 (stack)
+       mfpr    $P1LR,r3
+kacc2:
+       addl3   8(ap),r0,r1     # ending virtual address
+       ashl    $-9,r0,r0       # page number
+       ashl    $-9,r1,r1
+       bbc     $30,4(ap),kacc6
+       cmpl    r0,r3           # user stack
+       blss    kacerr          # address too low
+       brb     kacc4
+kacc6: cmpl    r1,r3           # compare last page to P0LR or SLR
+       bgeq    kacerr          # address too high
+kacc4: 
+       movl    (r2)[r0],r1
+       bbc     $31,r1,kacerr   # valid bit is off
+       cmpzv   $27,$4,r1,$1    # check protection code
+       bleq    kacerr          # no access allowed
+       tstb    12(ap)
+       bneq    kacc5           # only check read access
+       cmpzv   $27,$2,r1,$3    # check low 2 bits of prot code
+       beql    kacerr          # no write access
+kacc5:
+       aobleq  r1,r0,kacc4     # next page
+       movl    $1,r0           # no errors
+       ret
+kacerr:
+       clrl    r0              # error
+       ret
+
+# calculate physical address of user virtual address
+_realaddr:     .globl  _realaddr
+       .word   0x0000
+       movl    4(ap),r0        # virtual address
+       blss    raerr           # we don't map kernal virtual addresses
+       bbsc    $30,r0,rasseg           # stack segment address
+       mfpr    $P0BR,r1
+       mfpr    $P0LR,r2
+       ashl    $-9,r0,r3               # get page number
+       cmpl    r3,r2           # valid page number?
+       bgeq    raerr           # no
+ra1:
+       movl    (r1)[r3],r4     # get page table entry
+       bbc     $31,r4,raerr    # valid bit off - error
+       ashl    $9,r4,r5                # construct physical address
+       extzv   $0,$9,r0,r0             # offset within page
+       bisl2   r5,r0           # final physical address
+       ret
+rasseg:
+       mfpr    $P1BR,r1
+       mfpr    $P1LR,r2
+       ashl    $-9,r0,r3
+       cmpl    r3,r2
+       bgeq    ra1
+raerr:
+       clrl    r0
+       ret
+
+#
+#  unsigned int divide :
+#              (int) i = udiv( (int)dvdnd , (int) divis)
+#
+#  unsigned int remainder :
+#              (int) j = urem( (int)dvdnd , (int) divis)
+#
+       .text
+       .align  1
+       .globl  _udiv
+       .globl  _urem
+#
+_udiv :
+       .word   0  #  no reg save
+       movl    4(ap),r0  #  dividend
+       clrl    r1
+       ediv    8(ap),r0,r0,r1  #  quotient in r0
+       ret
+#
+       .align  1
+_urem :
+       .word   0
+       movl    4(ap),r0
+       clrl    r1
+       ediv    8(ap),r0,r1,r0  #  remainder in r0
+       ret
+# define user area virtual address
+       .set    physpages,1024
+       .set    kernsize,256     # number of page table entries allocated to kernal
+       .globl  _u
+       .set    usize,4         # size of user area, in pages
+       .set    _u,0x80000000 + kernsize*512
+       .set    u_ptoffset,256*4        # offset into _Sysmap of ptentries of _u
+       .set    CMAP1,u_ptoffset + 16*4 # offset into _Sysmap of 1st seg copy entry
+       .set    CMAP2,CMAP1+4   # ditto 2ed entry
+       .set    CADDR1,_u + 16*512      # virtual address of 1st copy segment
+       .set    CADDR2,CADDR1+512       # ditto second segment
+       .set    PHYSUBA,0x20006000      # real address of uba
+       .set    PHYSMBA0,0x20010000     # real addr of mba 0
+       .set    PHYSMBA1,0x20012000     # real addre of mba1
+       .set    PHYSUMEM,0x2013e000             # real address of unibus memory
+       .set    uba_offset,CMAP1+16*4   # offset in Sysmap of uba entries
+       .set    umem_offset,uba_offset+16*4     # ... unibus device registers
+       .set    mba0_offset,umem_offset+16*4    # ... massbus 0
+       .set    mba1_offset,mba0_offset+16*4    # ... massbus 1
+       .set    mba2_offset,mba1_offset+16*4    # ... massbus 2
+       .set    mba3_offset,mba2_offset+16*4    # ... massbus 3
+
+       .set    qsoff,0x140  #  offset to 'qsav' pcb in 'u' area
+       .set    ssoff,360       #offset to "ssav' in u_area
+
+
+#
+# Error messages
+#
+       .data
+
+emsg1:
+       .byte   0xa,0xa,0xa,0xd,0x54,0x52,0x41,0x50,0x20
+       .byte   0x46,0x52,0x4f,0x4d,0x20
+       .byte   0x4b,0x45,0x52,0x4e,0x41,0x4c,0x20
+       .byte   0x4d,0x4f,0x44,0x45,0xa,0xa,0xd,0x0
+
+emsg2:
+       .byte   0xa,0xa,0xa,0xd,0x54,0x52,0x41,0x50,0x20
+       .byte   0x52,0x45,0x54,0x55,0x52,0x4e,0x20
+       .byte   0x44,0x4f,0x20
+       .byte   0x4b,0x45,0x52,0x4e,0x41,0x4c,0x20
+       .byte   0x4d,0x4f,0x44,0x45,0xa,0xa,0xd,0x0
+
+SBImsg :
+       .byte   'S,'B,'I,' ,'f,'a,'u,'l,'t,' ,012,0
+UBAmsg :
+       .byte   'U,'B,'A,' ,'e,'r,'r,'o,'r,' ,'%,'x,012,0
+ZERmsg :
+       .byte   'Z,'e,'r,'o,' ,'V,'e,'c,'t,'o,'r,012,0
+#
+#      _Sysmap:
+#              system page table
+#
+#      structure:
+#              2 pages of page table entries
+#                      reserved for kernal text and data.
+#              1 additional page of page table entries
+#                      used in mapping the u area (16 entries),
+#                      utility entries (16 entries),
+#                      unibus adapter (16 entries),
+#                      unibus device memory (16 entries),
+#                      massbus adapter 0 (16 entries),
+#                      massbus adapter 1 (16 entries),
+#                      massbus adapter 2 (16 entries),
+#                      massbus adapter 3 (16 entries).
+#
+#
+
+       .align  2
+       .globl  _Sysmap
+_Sysmap:
+       .space  3*128*4         # 3 pages of page table entries for kernal
+       .set    Syssize,3*128           # number pt entries in sys page table
diff --git a/usr/src/slowsys/sys/machdep.c b/usr/src/slowsys/sys/machdep.c
new file mode 100644 (file)
index 0000000..c49822a
--- /dev/null
@@ -0,0 +1,185 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/acct.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/reg.h"
+#include "../h/mtpr.h"
+#include "../h/clock.h"
+#include "../h/buf.h"
+
+long   icode[] =
+{
+       0x9f19af9f,     /* pushab [&"init",0]; pushab */
+       0x02dd09af,     /* "/etc/init"; pushl $2 */
+       0xbc5c5ed0,     /* movl sp,ap; chmk */
+       0x2ffe110b,     /* $exec; brb .; "/ */
+       0x2f637465,     /* etc/ */
+       0x74696e69,     /* init */
+       0x00000000,     /* ";  0 */
+       0x00000014,     /* [&"init", */
+       0x00000000,     /* 0] */
+};
+int    szicode = sizeof(icode);
+/*
+ * Machine-dependent startup code
+ */
+startup(firstaddr)
+{
+       /*
+        * zero and free all of core
+        */
+
+       printf("real mem  = %d\n", maxmem*ctob(1) );
+       maxmem -= (firstaddr+USIZE);
+       mfree(coremap, maxmem, firstaddr+USIZE);
+       printf("avail mem = %d\n", maxmem*ctob(1));
+       if(MAXMEM < maxmem)
+               maxmem = MAXMEM;
+       mfree(swapmap, nswap, 1);
+       swplo--;
+       mbainit();              /* setup mba mapping regs map */
+       ubainit();              /* setup uba mapping regs map */
+}
+
+/*
+ * set up a physical address
+ * into users virtual address space.
+ */
+sysphys()
+{
+       register i, s, d;
+
+       if(!suser())
+               return;
+       u.u_error = EINVAL;
+}
+
+/*
+ * Start clock
+ */
+clkstart()
+{
+       mtpr(NICR, -16667);     /* 16.667 milli-seconds */
+       mtpr(ICCS,ICCS_RUN+ICCS_IE+ICCS_TRANS+ICCS_INT+ICCS_ERR);
+}
+
+clkreld()
+{
+       mtpr(ICCS, ICCS_RUN + ICCS_IE +ICCS_INT + ICCS_ERR);
+}
+
+
+/*
+ * Send an interrupt to process
+ */
+sendsig(p, n)
+{
+       register int *usp, *regs;
+       register int mask, r, spa, t;
+       int *s;
+
+       regs = u.u_ar0;
+       usp = (int *)regs[SP];
+       grow((unsigned)(usp-20));
+       mask = (fuword(p) & 0xfff) | 0x3f; /* get register save mask (save r0-r5) */
+       suword( (caddr_t) --usp, n);    /* sig # as param */
+       suword( (caddr_t) --usp, 1);    /* one parameters */
+       s = usp;
+       spa = ((int) usp) & 0x3;
+       if (spa) usp = (int *)((int) (usp - 1) & ~ 0x3);
+       t = 11;
+       for (r=0x800; r; r>>=1)
+               {
+               if (mask & r) suword((caddr_t) --usp, regs[t]);
+               t--;
+               }
+       suword( (caddr_t) --usp, regs[PC]);
+       suword( (caddr_t) --usp, regs[FP]);
+       suword( (caddr_t) --usp, regs[AP]);
+       suword( (caddr_t) --usp, (spa << 30) | (0x2 << 28)
+                               | (mask << 16) | (regs[PS] & 0xfff1));
+       suword( (caddr_t) --usp, 0);
+
+       regs[SP] = (int)usp;
+       regs[FP] = (int)usp;
+       regs[AP] = (int)s;
+       regs[PC] = p + 2;
+       regs[PS] &= ~ 0x1f;
+}
+
+caddr_t
+checkio(rw)
+register rw;
+{
+       register caddr_t realbase;
+
+       rw = ! rw;                      /* read disk => write core */
+       realbase = realaddr(u.u_base, rw, 3);           /* calculate physical address */
+       if (realbase == NULL)
+               goto bad;
+       if( useracc(u.u_base, u.u_count, rw))
+               return(realbase);
+    bad:
+       u.u_error = EFAULT;
+       return(NULL);
+}
+
+mtpr(regno, value)
+{
+       asm("   mtpr    8(ap),4(ap)");
+}
+
+mfpr(regno)
+{
+       asm("   mfpr    4(ap),r0");
+}
+
+/*
+ * Copy bytes within kernel
+ */
+bcopy(from,to,count)
+{
+       asm("   movc3   12(ap),*4(ap),*8(ap)");
+}
+
+/*
+ * Add a long word to a quad word
+ */
+add64(increment,lowtotal,hitotal)
+{
+       asm("   addl2   4(ap),*8(ap)");
+       asm("   adwc    $0,*12(ap)");
+}
+/*
+*  UNIBUS Address Space <-->  User Space transfer
+*/
+UNIcpy(uniadd,usradd,bknt,direct)
+short *uniadd , *usradd;
+{
+register short *from , *to;
+register int i;
+if (direct == B_READ) {
+       from = uniadd;
+       to = usradd ;
+       }
+else {
+       if (direct == B_WRITE) {
+               from = usradd;
+               to = uniadd ;
+               }
+       }
+for (i = (bknt>>1) ; i>0 ; i--)
+       (*to++) = (*from++);
+return(0);
+}
diff --git a/usr/src/slowsys/sys/main.c b/usr/src/slowsys/sys/main.c
new file mode 100644 (file)
index 0000000..5427cd3
--- /dev/null
@@ -0,0 +1,168 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/filsys.h"
+#include "../h/mount.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/proc.h"
+#include "../h/inode.h"
+#include "../h/seg.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/mtpr.h"
+#include "../h/page.h"
+# include "../h/clock.h"
+
+
+/*
+ * Initialization code.
+ * Called from cold start routine as
+ * soon as a stack and segmentation
+ * have been established.
+ * Functions:
+ *     clear and free user core
+ *     turn on clock
+ *     hand craft 0th process
+ *     call all initialization routines
+ *     fork - process 0 to schedule
+ *          - process 1 execute bootstrap
+ *
+ * loop at loc 13 (0xd) in user mode -- /etc/init
+ *     cannot be executed.
+ */
+main(firstaddr)
+{
+
+       startup(firstaddr);
+
+       /*
+        * set up system process
+        */
+
+       proc[0].p_addr = firstaddr;
+       proc[0].p_size = USIZE;
+       proc[0].p_stat = SRUN;
+       proc[0].p_flag |= SLOAD|SSYS;
+       proc[0].p_nice = NZERO;
+       u.u_procp = &proc[0];
+       u.u_cmask = CMASK;
+       estabur(0, 0, 0, 0, 0);
+       clkstart();
+
+       /*
+        * Initialize devices and
+        * set up 'known' i-nodes
+        */
+
+       cinit();
+       binit();
+       iinit();
+       rootdir = iget(rootdev, (ino_t)ROOTINO);
+       rootdir->i_flag &= ~ILOCK;
+       u.u_cdir = iget(rootdev, (ino_t)ROOTINO);
+       u.u_cdir->i_flag &= ~ILOCK;
+       u.u_rdir = NULL;
+
+       /*
+        * make init process
+        * enter scheduling loop
+        * with system process
+        */
+
+       if(newproc()) {
+               expand(USIZE + btoc(szicode));
+               u.u_dsize = btoc(szicode);
+               estabur(0, btoc(szicode), 0, 0, RO);
+               copyout((caddr_t)icode, (caddr_t)0, szicode);
+               /*
+                * Return goes to loc. 0 of user init
+                * code just copied out.
+                */
+               return;
+       }
+       sched();
+}
+
+/*
+ * iinit is called once (from main)
+ * very early in initialization.
+ * It reads the root's super block
+ * and initializes the current date
+ * from the last modified date.
+ *
+ * panic: iinit -- cannot read the super
+ * block. Usually because of an IO error.
+ */
+iinit()
+{
+       register struct buf *cp, *bp;
+       register struct filsys *fp;
+       register unsigned i , j ;
+
+       (*bdevsw[major(rootdev)].d_open)(rootdev, 1);
+       bp = bread(rootdev, SUPERB);
+       cp = geteblk();
+       if(u.u_error)
+               panic("iinit");
+       bcopy(bp->b_un.b_addr, cp->b_un.b_addr, sizeof(struct filsys));
+       brelse(bp);
+       mount[0].m_bufp = cp;
+       mount[0].m_dev = rootdev;
+       fp = cp->b_un.b_filsys;
+       fp->s_flock = 0;
+       fp->s_ilock = 0;
+       fp->s_ronly = 0;
+       /* on boot, read VAX TODR register (GMT 10 ms.
+       *       clicks into current year) and set software time
+       *       in 'int time' (GMT seconds since year YRREF)
+       */
+       for (i = 0 , j = YRREF ; j < YRCURR ; j++)
+               i += (SECYR + (j%4?0:SECDAY)) ;
+       time = udiv(mfpr(TODR),100) + i ;
+}
+
+/*
+ * This is the set of buffers proper, whose heads
+ * were declared in buf.h.  There can exist buffer
+ * headers not pointing here that are used purely
+ * as arguments to the I/O routines to describe
+ * I/O to be done-- e.g. swbuf for
+ * swapping.
+ */
+char   buffers[NBUF][BSIZE+BSLOP];
+
+/*
+ * Initialize the buffer I/O system by freeing
+ * all buffers and setting all device buffer lists to empty.
+ */
+binit()
+{
+       register struct buf *bp;
+       register struct buf *dp;
+       register int i;
+       struct bdevsw *bdp;
+
+       bfreelist.b_forw = bfreelist.b_back =
+           bfreelist.av_forw = bfreelist.av_back = &bfreelist;
+       for (i=0; i<NBUF; i++) {
+               bp = &buf[i];
+               bp->b_dev = NODEV;
+               bp->b_un.b_addr = buffers[i];
+               bp->b_back = &bfreelist;
+               bp->b_forw = bfreelist.b_forw;
+               bfreelist.b_forw->b_back = bp;
+               bfreelist.b_forw = bp;
+               bp->b_flags = B_BUSY;
+               brelse(bp);
+       }
+       for (bdp = bdevsw; bdp->d_open; bdp++) {
+               dp = bdp->d_tab;
+               if(dp) {
+                       dp->b_forw = dp;
+                       dp->b_back = dp;
+               }
+               nblkdev++;
+       }
+}
diff --git a/usr/src/slowsys/sys/malloc.c b/usr/src/slowsys/sys/malloc.c
new file mode 100644 (file)
index 0000000..af71008
--- /dev/null
@@ -0,0 +1,81 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+
+/*
+ * Allocate 'size' units from the given
+ * map. Return the base of the allocated
+ * space.
+ * In a map, the addresses are increasing and the
+ * list is terminated by a 0 size.
+ * The core map unit is 512 bytes; the swap map unit
+ * is 512 bytes.
+ * Algorithm is first-fit.
+ */
+malloc(mp, size)
+struct map *mp;
+{
+       register unsigned int a;
+       register struct map *bp;
+
+       for (bp=mp; bp->m_size; bp++) {
+               if (bp->m_size >= size) {
+                       a = bp->m_addr;
+                       bp->m_addr += size;
+                       if ((bp->m_size -= size) == 0) {
+                               do {
+                                       bp++;
+                                       (bp-1)->m_addr = bp->m_addr;
+                               } while ((bp-1)->m_size = bp->m_size);
+                       }
+                       return(a);
+               }
+       }
+       return(0);
+}
+
+/*
+ * Free the previously allocated space aa
+ * of size units into the specified map.
+ * Sort aa into map and combine on
+ * one or both ends if possible.
+ */
+mfree(mp, size, a)
+struct map *mp;
+register unsigned int a;
+{
+       register struct map *bp;
+       register unsigned int t;
+
+       if ((bp = mp)==coremap && runin) {
+               runin = 0;
+               wakeup((caddr_t)&runin);        /* Wake scheduler when freeing core */
+       }
+       for (; bp->m_addr<=a && bp->m_size!=0; bp++);
+       if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
+               (bp-1)->m_size += size;
+               if (a+size == bp->m_addr) {
+                       (bp-1)->m_size += bp->m_size;
+                       while (bp->m_size) {
+                               bp++;
+                               (bp-1)->m_addr = bp->m_addr;
+                               (bp-1)->m_size = bp->m_size;
+                       }
+               }
+       } else {
+               if (a+size == bp->m_addr && bp->m_size) {
+                       bp->m_addr -= size;
+                       bp->m_size += size;
+               } else if (size) {
+                       do {
+                               t = bp->m_addr;
+                               bp->m_addr = a;
+                               a = t;
+                               t = bp->m_size;
+                               bp->m_size = size;
+                               bp++;
+                       } while (size = t);
+               }
+       }
+}
diff --git a/usr/src/slowsys/sys/mba.c b/usr/src/slowsys/sys/mba.c
new file mode 100644 (file)
index 0000000..a1b00ac
--- /dev/null
@@ -0,0 +1,79 @@
+#
+/*
+ */
+
+#include "../h/param.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/seg.h"
+#include "../h/page.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/mba.h"
+#include "../h/mtpr.h"
+
+/*
+ * startup routine for MBA controllers.
+ */
+#define        MBAWCOM 0x30
+#define        MBARCOM 0x38
+#define        GO      01
+
+int mbaboff;
+
+mbastart(bp, adcr)
+register struct buf *bp;
+int *adcr;
+{
+       register int vaddr, com, *io, num;
+       register struct mba_regs *mbap;
+       int *pt, pf;
+       extern int mbanum[], *mbaloc[];
+       extern char buffers[][];
+
+       mbap = (struct mba_regs *)(mbaloc[mbanum[major(bp->b_dev)]]);
+       if ( (bp->b_flags & B_PHYS) == 0 ) {
+               vaddr = (bp->b_un.b_addr - (char *)buffers) + mbaboff;
+       } else {
+               io = (int *)mbap;
+               io += (MBA_MAP + 128*4)/4;
+               num = btoc(bp->b_bcount) + 1;
+               pf = (int)bp->b_un.b_addr >> 9;
+               while ( num-->0)
+                       *io++ = 0x80000000 | pf++;
+               vaddr = (128 << 9) | ((int)bp->b_un.b_addr & 0x1ff);
+       }
+       mbap->mba_sr = -1;      /* clear status (error) bits */
+       mbap->mba_bcr = -bp->b_bcount;
+       mbap->mba_var = vaddr;
+       if (bp->b_flags & B_READ)
+               com = MBARCOM | GO;
+       else
+               com = MBAWCOM | GO;
+
+       *adcr = com;            /* set cmd in device control and status register */
+}
+
+mbainit()
+{
+       register int *io0, *io1, *b, t, j;
+       extern int Sysmap[], *mbaloc[];
+       extern char buffers[][];
+
+       io0 = mbaloc[0] + (MBA_MAP/4);
+       io1 = mbaloc[1] + (MBA_MAP/4);
+       b = Sysmap + ((((int) buffers)>>9)&0x1fffff);
+       j = NBUF + ((int)buffers & 0x1ff ? 1 : 0);
+       do {
+               t = 0x80000000 | (*b++ & 0x1fffff);
+               *io0++ = t;
+               *io1++ = t;
+       } while (--j>0);
+       *io0 = 0;               /* invalidate next entry */
+       *io1 = 0;
+       mbaboff = (int)buffers & 0x1ff;
+}
diff --git a/usr/src/slowsys/sys/mem.c b/usr/src/slowsys/sys/mem.c
new file mode 100644 (file)
index 0000000..a2b8137
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *     Memory special file
+ *     minor device 0 is physical memory
+ *     minor device 1 is kernel memory 
+ *     minor device 2 is EOF/RATHOLE
+ */
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/page.h"
+#include "../h/mtpr.h"
+
+int mmapinuse, mmapwant;
+
+mmread(dev)
+{
+       register char *p;
+       register c;
+       extern int *mmap;
+       extern char *vmmap;
+
+       if(minor(dev) == 2)
+               return;
+       if( minor(dev) == 1 ) {
+               if( kernacc(u.u_offset, u.u_count, B_READ)
+           && !copyout(u.u_offset, u.u_base, u.u_count) ) {
+               c = u.u_count;
+               u.u_count = 0;
+               u.u_base += c;
+               u.u_offset += c;
+       } else 
+               u.u_error = EFAULT;
+       return;
+       }
+
+       if( minor(dev) == 0) {
+
+               spl7();
+               while( mmapinuse ) {
+                       mmapwant++;
+                       sleep(&mmapwant, PRIBIO);
+               }
+               mmapinuse = 1;
+               spl0();
+               while (u.u_count > 0 && u.u_error == 0) {
+                       c = (int) u.u_offset >> 9;
+                       if( c < 0 || c > PHYSPAGES ) {
+                               u.u_error = EFAULT;
+                               break;
+                       }
+                       *mmap = c | (PG_V | PG_KR);
+                       mtpr(TBIS, vmmap);
+                       copyout(vmmap+((int)u.u_offset & 0x1ff), u.u_base, c=min(512-((int)u.u_offset & 0x1ff), u.u_count));
+                       u.u_count -= c;
+                       u.u_base += c;
+                       u.u_offset += c;
+               }
+               spl7();
+               mmapinuse = 0;
+               if( mmapwant ) {
+                       mmapwant = 0;
+                       wakeup( &mmapwant );
+               }
+               spl0();
+       return;
+       }
+if (minor(dev) == 3) { /* UNIBUS access */
+       if ((!kernacc(u.u_offset,u.u_count,B_READ)) ||
+       (!useracc(u.u_base,u.u_count,B_READ)) ||
+       UNIcpy(u.u_offset,u.u_base,u.u_count,B_READ))
+               u.u_error = EFAULT;
+       else {
+               u.u_offset += u.u_count;
+               u.u_base += u.u_count;
+               u.u_count = 0;
+               }
+       return;
+       }
+}
+
+mmwrite(dev)
+{
+       register char *p;
+       register c;
+
+       if(minor(dev) == 2) {
+               c = u.u_count;
+               u.u_count = 0;
+               u.u_offset += c;
+               return;
+       }
+       /*  kernel virt mem */
+       if (minor(dev) == 1) {
+               if ((!kernacc(u.u_offset,u.u_count,B_WRITE)) || copyin(u.u_base,u.u_offset,u.u_count))
+                       u.u_error = EFAULT;
+               else {
+                       u.u_offset += u.u_count;
+                       u.u_base += u.u_count;
+                       u.u_count = 0 ;
+                       }
+               return;
+               }
+       if (minor(dev) == 3) { /* UNIBUS access */
+               if ((!kernacc(u.u_offset,u.u_count,B_WRITE)) ||
+               (!useracc(u.u_base,u.u_count,B_WRITE)) ||
+               UNIcpy(u.u_offset,u.u_base,u.u_count,B_WRITE))
+                       u.u_error = EFAULT;
+               else {
+                       u.u_offset += u.u_count;
+                       u.u_base += u.u_count;
+                       u.u_count = 0;
+                       }
+               return;
+               }
+}
diff --git a/usr/src/slowsys/sys/mx1.c b/usr/src/slowsys/sys/mx1.c
new file mode 100644 (file)
index 0000000..657389f
--- /dev/null
@@ -0,0 +1,363 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.h"
+#include "../h/proc.h"
+#include "../h/tty.h"
+#include "../h/inode.h"
+#include "../h/mx.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+
+struct chan    chans[NCHANS];
+struct group   *groups[NGROUPS];
+int    mpxline;
+struct chan *xcp();
+dev_t  mpxdev  = -1;
+
+
+char   mcdebugs[NDEBUGS];
+
+
+struct chan *
+challoc(index)
+register index;
+{
+register s;
+register struct chan *cp;
+
+       s = spl6();
+       for(cp=chans; cp< &chans[NCHANS]; cp++)
+               if(cp->c_group==NULL) {
+                       cp->c_index = index;
+                       cp->c_pgrp = 0;
+                       splx(s);
+                       return(cp);
+               }
+       splx(s);
+       return(NULL);
+}
+
+
+gpalloc()
+{
+register i,s;
+
+       s = spl6();
+       for(i = NGROUPS-1; i>=0; i--)
+               if (groups[i]==NULL) {
+                       groups[i]++;
+                       break;
+               }
+       splx(s);
+       return(i);
+}
+
+struct chan *
+addch(ip)
+struct inode *ip;
+{
+register struct chan *cp;
+register struct group *gp;
+register i;
+
+       plock(ip);
+       gp = &ip->i_un.i_group;
+       for(i=0;i<NINDEX;i++) {
+               cp = (struct chan *)gp->g_chans[i];
+               if (cp == NULL) {
+                       if ((cp=challoc(i)) != NULL) {
+                               gp->g_chans[i] = cp;
+                               cp->c_group = gp;
+                       }
+                       break;
+               }
+               cp = NULL;
+       }
+       prele(ip);
+       return(cp);
+}
+
+
+
+
+/*
+ * mpxchan system call
+ */
+mpxchan()
+{
+struct inode *ip,*gip;
+register int i;
+extern mxopen(), mcread();
+extern struct chan *addch();
+dev_t  dev;
+struct tty *tp;
+struct file *fp,*chfp,*gfp;
+struct chan *cp;
+struct group *gp;
+
+       /*
+        * common setup code.
+        */
+       i = u.u_arg[3];
+       gp = NULL;
+       switch(i) {
+       case NPGRP:
+               if (u.u_arg[1] < 0)
+                       goto sw;
+       case CHAN:
+       case JOIN:
+       case EXTR:
+       case ATTACH:
+       case DETACH:
+       case CSIG:
+               gfp = getf(u.u_arg[1]);
+               if (gfp==NULL)
+                       goto bad;
+               gip = gfp->f_inode;
+               gp = &gip->i_un.i_group;
+               if (gp->g_inode != gip)
+                       goto bad;
+       }
+
+sw:
+       switch(i) {
+       /*
+        * creat a null group
+        * return a file descriptor
+        */
+       case MPX:
+       case MPXN:
+               if (mpxdev < 0) {
+                       for(i=0; linesw[i].l_open; i++) 
+                               if (linesw[i].l_read == mcread) {
+                                       mpxline = i;
+                                       goto found1;
+                               }
+                       goto bad;
+
+               found1:
+                       for(i=0; cdevsw[i].d_open; i++) {
+                               if (cdevsw[i].d_open == mxopen)
+                                       goto found2;
+                       }
+               bad:
+                       u.u_error = ENXIO;
+                       return;
+               found2:
+                       mpxdev = (dev_t)(i<<8);
+                       i = u.u_arg[3];
+               }
+               if (i==MPXN) {
+                       if ((ip=ialloc(rootdev))==NULL)
+                               goto bad;
+                       ip->i_mode = (u.u_arg[1]&0777)+IFCHR;
+                       ip->i_flag = IACC|IUPD|ICHG;
+                       ip->i_nlink = 1;
+                       goto merge;
+               }
+               ip = namei(uchar,1);
+               if (ip != NULL) {
+                       u.u_error = EEXIST;
+                       iput(ip);
+                       return;
+               }
+               if (u.u_error)
+                       return;
+               ip = maknode((u.u_arg[1]&0777)+IFCHR);
+               if (ip == NULL)
+                       return;
+       merge:
+               if ((i = gpalloc()) < 0) {
+                       iput(ip);
+                       goto bad;
+               }
+               ip->i_un.i_rdev = (daddr_t)(mpxdev+i);
+               gp = &ip->i_un.i_group;
+               groups[i] = gp;
+               gp->g_inode = ip;
+               gp->g_state = COPEN;
+               gp->g_group = NULL;
+               gp->g_index = 0;
+               gp->g_rotmask = 1;
+               gp->g_rot = 0;
+               gp->g_datq = 0;
+               open1(ip,FREAD+FWRITE,2);
+               if (u.u_error) {
+                       groups[i] = NULL;
+                       iput(ip);
+                       goto bad;
+               }
+               ip->i_mode |= IFMPC;
+               ip->i_count++;
+               fp = u.u_ofile[u.u_r.r_val1];
+               fp->f_flag |= FMP;
+               fp->f_un.f_chan = NULL;
+               for(i=0;i<NINDEX;)
+                       gp->g_chans[i++] = NULL;
+               return;
+       /*
+        * join file descriptor (arg 0) to group (arg 1)
+        * return channel number
+        */
+       case JOIN:
+               if ((fp=getf(u.u_arg[0]))==NULL)
+                       goto bad;
+               ip = fp->f_inode;
+               i = ip->i_mode & IFMT;
+               if (i == IFMPC) {
+                       mlink(fp->f_inode, gp);
+                       return;
+               }
+               if (i != IFCHR) 
+                       goto bad;
+               dev = (dev_t)ip->i_un.i_rdev;
+               tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
+               if (tp==NULL || tp->t_chan)
+                       goto bad;
+               if ((cp=addch(gip))==NULL)
+                       goto bad;
+               tp->t_chan = cp;
+               cp->c_ottyp = cp->c_ittyp = tp;
+               cp->c_iline = cp->c_oline = tp->t_line;
+               cp->c_flags = XGRP+TTYO;
+               u.u_r.r_val1 = cp->c_index;
+               return;
+       /*
+        * attach channel (arg 0) to group (arg 1)
+        */
+       case ATTACH:
+               cp = xcp(gp, u.u_arg[0]);
+               if (cp==NULL)
+                       goto bad;
+               u.u_r.r_val1 = cpx(cp);
+               wakeup((caddr_t)cp);
+               return;
+       case DETACH:
+               cp = xcp(gp, u.u_arg[0]);
+               if (cp==NULL)
+                       goto bad;
+               cp->c_flags |= WCLOSE;
+               wakeup((caddr_t)cp);
+               return;
+       /*
+        * extract channel (arg 0) from group (arg 1)
+        * using X side (arg 2 zero) otherwise Y side
+        */
+       case EXTR:
+               cp = xcp(gp, u.u_arg[0]);
+               if (cp==NULL) {
+                       goto bad;
+               }
+               if ((fp = falloc()) == NULL) {
+                       return;
+               }
+               fp->f_inode = gip;
+               fp->f_un.f_chan = cp;
+               fp->f_flag = (u.u_arg[2]) ? (FREAD+FWRITE+FMPY) : (FREAD+FWRITE+FMPX);
+               return;
+       /*
+        * make new chan on group (arg 1)
+        */
+       case CHAN:
+               if ((cp=addch(gip))==NULL)
+                       goto bad;
+               cp->c_flags = XGRP;
+               cp->c_ittyp = cp->c_ottyp = (struct tty *)cp;
+               cp->c_iline = cp->c_oline = mpxline;
+               u.u_r.r_val1 = cp->c_index;
+               return;
+       /*
+        * connect fd (arg 0) to channel fd (arg 1)
+        * (arg 2 <  0) => fd to chan only
+        * (arg 2 >  0) => chan to fd only
+        * (arg 2 == 0) => both directions
+        */
+       case CONNECT:
+               if ((fp=getf(u.u_arg[0]))==NULL)
+                       goto bad;
+               if ((chfp=getf(u.u_arg[1]))==NULL)
+                       goto bad;
+               ip = fp->f_inode;
+               i = ip->i_mode&IFMT;
+               if (i!=IFMPC)
+                       goto bad;
+               dev = (dev_t)ip->i_un.i_rdev;
+               tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
+               if (tp==NULL)
+                       goto bad;
+               if (!(chfp->f_flag&FMPY)) {
+                       goto bad;
+               }
+               cp = chfp->f_un.f_chan;
+               if (cp==NULL) {
+                       goto bad;
+               }
+               i = u.u_arg[2];
+               if (i>=0) {
+                       cp->c_ottyp = tp;
+                       cp->c_oline = tp->t_line;
+               }
+               if (i<=0)  {
+                       tp->t_chan = cp;
+                       cp->c_ittyp = tp;
+                       cp->c_iline = tp->t_line;
+               }
+               return;
+       case NPGRP: {
+               register struct proc *pp;
+
+               if (gp != NULL) {
+                       cp = xcp(gp, u.u_arg[0]);
+                       if (cp==NULL)
+                               goto bad;
+               }
+               pp = u.u_procp;
+               pp->p_pgrp = pp->p_pid;
+               if (u.u_arg[2])
+                       pp->p_pgrp = u.u_arg[2];
+               if (gp != NULL)
+                       cp->c_pgrp = pp->p_pgrp;
+               return;
+       }
+       case CSIG:
+               cp = xcp(gp, u.u_arg[0]);
+               if (cp==NULL)
+                       goto bad;
+               signal(cp->c_pgrp, u.u_arg[2]);
+               return;
+       case DEBUG:
+               i = u.u_arg[0];
+               if (i<0 || i>NDEBUGS)
+                       return;
+               mcdebugs[i] = u.u_arg[1];
+               if (i==ALL)
+                       for(i=0;i<NDEBUGS;i++)
+                               mcdebugs[i] = u.u_arg[1];
+               return;
+       default:
+               goto bad;
+       }
+}
+
+
+
+mlink(sub,master)
+struct group *sub, *master;
+{
+register i;
+
+
+       for(i=0;i<NINDEX;i++) {
+               if (master->g_chans[i] != NULL)
+                       continue;
+               master->g_chans[i] = (struct chan *)sub;
+               sub->g_group = master;
+               sub->g_index = i;
+               u.u_r.r_val1 = i;
+               return;
+       }
+       u.u_error = ENXIO;
+       return;
+}
diff --git a/usr/src/slowsys/sys/mx2.c b/usr/src/slowsys/sys/mx2.c
new file mode 100644 (file)
index 0000000..05ad549
--- /dev/null
@@ -0,0 +1,693 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/tty.h"
+#include "../h/inode.h"
+#include "../h/mx.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+/*
+ * multiplexor driver
+ */
+struct chan    chans[NCHANS];
+struct group   *groups[NGROUPS];
+int    mpxline;
+struct chan *xcp();
+struct chan *addch();
+struct chan *nextcp();
+
+int    chzero;
+short  cmask[16]       ={
+       01,     02,     04,
+       010,    020,    040,
+       0100,   0200,   0400,
+       01000,  02000,  04000,
+       010000, 020000, 040000, 0100000
+};
+
+char mcdebugs[NDEBUGS];
+mxopen(dev,flag)
+{
+register struct group *gp;
+register struct file *fp;
+register struct chan *cp;
+int d;
+
+struct inode *ip;
+       d = minor(dev);
+       if (d>=NGROUPS) {
+       bad:
+               u.u_error = ENXIO;
+               printf("bad mxopen\n");
+               return;
+       }
+       gp = groups[d];
+       if (gp->g_state == COPEN) {
+               gp->g_state = INUSE+ISGRP;
+               return;
+       }
+       if (!(gp->g_state&INUSE)) 
+               goto bad;
+       fp = u.u_ofile[u.u_r.r_val1];
+       if (fp->f_inode != gp->g_inode) 
+               goto bad;
+       if ((cp=addch(gp->g_inode))==NULL)
+               goto bad;
+       cp->c_flags = XGRP;
+       cp->c_ottyp = cp->c_ittyp = (struct tty *)cp;
+       cp->c_iline = cp->c_oline = mpxline;
+       fp->f_flag |= FMPY;
+       fp->f_flag |= FREAD+FWRITE;
+       fp->f_un.f_chan = cp;
+       cp->c_pgrp = u.u_procp->p_pgrp;
+#ifdef CTRACE
+       printf("open pgrp %d\n",cp->c_pgrp);
+#endif
+       scontrol(cp, M_WATCH+(cp->c_index<<8), u.u_uid);
+       sleep((caddr_t)cp,TTIPRI);
+       if (cp->c_flags & WCLOSE) {
+               printf("WCLOSE on %o\n",cp);
+               chfree(cp,0);
+               goto bad;
+       }
+       cp->c_fy = fp;
+}
+
+
+mxclose(dev,cp)
+dev_t  dev;
+struct chan *cp;
+{
+register i;
+register struct group *gp;
+register struct inode *ip;
+
+       gp = groups[minor(dev)];
+       ip = gp->g_inode;
+       if (ip==NULL) {
+               if (cp==NULL || (int)cp==FWRITE)
+               printf("bad close gp %o gpi %o ip %o ipg %o\n",
+                       gp,gp->g_inode,ip,ip->i_un.i_group);
+               if (cp==NULL)
+                       return;
+       }
+       if (cp!=NULL && (int)cp!=FWRITE) {
+               i = cp->c_index;
+               if (!cp->c_flags&WCLOSE) {
+                       chfree(cp,1);
+                       scontrol(cp, M_CLOSE, 0);
+printf("x1 close\n");
+               } else {
+                       chfree(cp,0);
+#ifdef CTRACE
+                       printf("WC close\n");
+#endif
+               }
+               gp->g_chans[i] = NULL;
+               cp->c_pgrp = 0;
+               cp->c_group = NULL;
+               cp->c_flags |= WCLOSE;
+               return;
+       }
+       if ((ip->i_mode&IFMT)!=IFMPC) {
+               printf("close on inode %o\n",ip);
+               return;
+       }
+       for(i=0;i<NINDEX;i++) {
+               if ((cp=gp->g_chans[i])!=NULL) {
+                       if (cp->c_flags&ISGRP) {
+                               ((struct group *)cp)->g_state &= ~ISGRP;
+                               ((struct group *)cp)->g_group = NULL;
+                               continue;
+                       }
+                       cp->c_flags |= WCLOSE;
+                       wakeup((caddr_t)cp);
+                       signal(cp->c_pgrp,SIGHUP);
+                       chfree(cp,0);
+                       if (gp->g_chans[i])
+                               printf("chfree didn't clear inode\n");
+               }
+       }
+       gp->g_state = NULL;
+       groups[minor(dev)] = NULL;
+       i = ip->i_mode;
+       i &= ~IFMT;
+       i |= IFCHR;
+       ip->i_mode = i;
+       ip->i_flag |= IUPD|ICHG;
+       iput(ip);
+}
+
+
+mxread(dev)
+{
+register struct group *gp;
+struct clist *q;
+struct chan *cp;
+register i;
+struct file *fp;
+struct header h;
+caddr_t        base;
+unsigned count;
+int    s,xfr,more;
+int esc;
+
+       i = minor(dev);
+       if (i>=NGROUPS) {
+               u.u_error = ENXIO;
+               return;
+       }
+       gp = groups[i];
+       fp = getf(u.u_arg[0]);
+       if ((fp->f_flag&FMP)!=FMP) {
+               msread(fp,gp);
+               return;
+       }
+
+       s = spl6();
+       while (gp->g_datq == 0) {
+
+               sleep((caddr_t)&gp->g_datq, TTIPRI);
+       }
+
+       while (gp->g_datq && u.u_count >= CNTLSIZ) {
+               splx(s);
+               esc = 0;
+               cp = nextcp(gp);
+               if (cp==NULL) {
+                       continue;
+               }
+               if (cp->c_ctlx.c_cc)
+                       esc = 2;
+               base = u.u_base;
+               count = u.u_count;
+               u.u_base += HDRSIZE + esc;
+               u.u_count -= HDRSIZE + esc;
+               xfr = u.u_count;
+               more = (*linesw[cp->c_iline].l_read)(cp->c_ittyp);
+               if (esc || more > 0) {
+                       sdata(cp);
+               }
+               if (more<0) {
+printf("m<0\n");
+printf("x2 close\n");
+                       scontrol(cp, M_CLOSE, 0);
+               }
+               xfr -= u.u_count;
+               if (xfr==0) {
+                       u.u_base = base;
+                       u.u_count = count;
+                       chzero++;
+                       continue;
+               }
+               h.index = cpx(cp);
+               if (esc) {
+                       h.count = 0;
+                       h.ccount = xfr;
+               } else
+                       h.count = xfr;
+               if (xfr&1) {
+                       u.u_base++;
+                       u.u_count--;
+               }
+               copyout(&h, base, HDRSIZE+esc);
+
+               q = &cp->cx.datq;
+               if (cp->c_flags&BLOCK && esc==0) {
+                       if (q->c_cc<25) {
+                               wakeup((caddr_t)q+1);
+                               cp->c_flags &= ~BLOCK;
+                       } else {
+                       }
+               }
+               if (cp->c_flags&WFLUSH)
+                       wakeup((caddr_t)q+2);
+               s = spl6();
+       }
+}
+
+
+mcread(cp)
+register struct chan *cp;
+{
+register struct clist *q;
+register c;
+
+
+       if (cp->c_ctlx.c_cc)
+               q = &cp->c_ctlx; else
+               q = &cp->cx.datq;
+
+       while( (c=getc(q)) >= 0) {
+               passc(c);
+       }
+       return(q->c_cc);
+
+}
+
+msread(fp, gp)
+struct file *fp;
+struct group *gp;
+{
+register struct clist *q;
+register struct chan *cp;
+register i;
+
+       cp = fp->f_un.f_chan;
+       q = (fp->f_flag&FMPX) ? &cp->cx.datq : &cp->cy.datq;
+       i = spl6();
+       if (!q->c_cc) {
+               if (cp->c_flags&WCLOSE) {
+                       printf("ms sees it %o\n",cp);
+                       u.u_error = ENXIO;
+                       return;
+               }
+               sleep((caddr_t)q,TTIPRI);
+       }
+       splx(i);
+       i = 0;
+       while(u.u_count && q->c_cc) {
+               passc(getc(q));
+               i++;
+       }
+       if (cp->c_flags&SIGBLK && q->c_cc < 20) {
+               cp->c_flags &= ~SIGBLK;
+               if (cp->c_flags&ENAMSG) 
+                       scontrol(cp, M_UBLK, 0); else
+                       wakeup((caddr_t)q);
+       }
+       if (cp->c_flags&WFLUSH)
+               wakeup((caddr_t)q+2);
+}
+
+
+mxwrite(dev)
+{
+register i;
+register struct chan *cp;
+struct header h;
+struct file *fp;
+struct group *gp;
+int    ucount;
+caddr_t        ubase;
+
+       i = minor(dev);
+       if (i>=NGROUPS) {
+               u.u_error = ENXIO;
+               return;
+       }
+       gp = groups[i];
+       fp = getf(u.u_arg[0]);
+       if ((fp->f_flag&FMP)!=FMP) {
+               ucount = mswrite(fp,gp);
+               return;
+       }
+       while (u.u_count) {
+               iomove(&h, sizeof(struct header), B_WRITE);
+/*
+               if (count==0) {
+                       esc++;
+                       h.count = h.ccount;
+               }
+*/
+               cp = xcp(gp, h.index);
+               if (cp==NULL)  {
+printf("nullo %o %o\n",cp,chans);
+                       u.u_count -= h.count;
+                       u.u_base += h.count;
+                       continue;
+               }
+               ucount = u.u_count;
+               ubase = u.u_base;
+               u.u_count = h.count;
+               u.u_base = h.addr;
+               (*linesw[cp->c_oline].l_write)(cp->c_ottyp);
+               u.u_count = ucount;
+               u.u_base = ubase;
+       }
+}
+
+
+mcwrite(cp)
+register struct chan *cp;
+{
+register struct clist *q;
+register c;
+int    s;
+
+       q = &cp->cy.datq;
+
+       while ((c=cpass())>=0) {
+               s = spl6();
+               while (q->c_cc > 100) {
+                       cp->c_flags |= SIGBLK;
+                       splx(s);
+                       if (cp->c_flags&ENAMSG) {
+                               scontrol(cp, M_BLK, (short)u.u_count);
+                               wakeup((caddr_t)q);
+                               while (cpass()>=0);
+                               return;
+                       } else
+                               sleep((caddr_t)q, TTOPRI);
+
+               }
+               splx(s);
+               putc(c, q);
+       }
+       wakeup((caddr_t)q);
+}
+
+
+mcttwrite(tp,cc)
+register struct tty *tp;
+register cc;
+{
+register c;
+struct chan *cp;
+
+       if ((tp->t_state&CARR_ON)==0)
+               return;
+       while (cc && (c=cpass())>=0) {
+               spl5();
+               if (tp->t_outq.c_cc > 10) {
+                       ttstart(tp);
+                       spl0();
+                       cp = tp->t_chan;
+                       cp->c_flags |= SIGBLK;
+                       scontrol(cp, M_BLK, cc);
+                       while (cc-- && cpass()>=0);
+                       return;
+               }
+               spl0();
+               ttyoutput(c,tp);
+               cc--;
+       }
+       ttstart(tp);
+}
+mcttstart(tp)
+struct tty *tp;
+{
+register struct chan *cp;
+
+       cp = tp->t_chan;
+       if (cp->c_flags&(BLKMSG+ENAMSG)) {
+               cp->c_flags &= ~BLKMSG;
+               scontrol(cp, M_UBLK, 0);
+       }
+}
+mswrite(fp,gp)
+struct file *fp;
+struct group *gp;
+{
+register struct clist *q;
+struct chan *cp;
+register c;
+int cc;
+
+       cp = fp->f_un.f_chan;
+       q = (fp->f_flag&FMPX) ? &cp->cy.datq : &cp->cx.datq;
+       cc = 0;
+       while((c=cpass())>=0) {
+               spl6();
+               if (cp->c_flags&WCLOSE) {
+               bad:
+                       u.u_error = ENXIO;
+                       printf("ms write sees it %o\n",cp);
+                       return(cc);
+               }
+               while (q->c_cc>100) {
+                       if (cp->c_flags&WCLOSE)
+                               goto bad;
+                       sdata(cp);
+/*
+                       if (q->c_cc) {
+                               printf("choops\n");
+                               sdata(cp);
+                               printf("sent\n");
+                       }
+*/
+                       cc = 0;
+                       cp->c_flags |= BLOCK;
+                       sleep((caddr_t)q+1,TTOPRI);
+               }
+               spl0();
+               if (putc(c,q)>=0)
+                       cc++; else
+                       printf("qe\n");
+       }
+       if (fp->f_flag&FMPX) {
+               if (cp->c_flags&YGRP) 
+                       sdata(cp); else
+                       wakeup((caddr_t)q);
+       } else {
+               if (cp->c_flags&XGRP) 
+                       sdata(cp); else
+                       wakeup((caddr_t)q);
+       }
+       return(cc);
+}
+
+
+
+mxioctl(dev, cmd, addr, flag)
+caddr_t addr;
+{
+/*
+       u.u_error = ENOTTY;
+*/
+}
+
+
+
+
+chfree(cp, flag)
+register struct chan *cp;
+{
+register struct tty *tp;
+struct group *gp;
+struct inode *ip;
+
+       if (chclear(cp))
+               goto out;
+       tp = cp->c_ittyp;
+       if (tp->t_chan == cp) {
+               cp->c_ittyp = NULL;
+               tp->t_chan = NULL;
+               if (flag && cp->c_iline==0)
+                       wflushtty(tp); else
+                       flushtty(tp);
+       }
+       if (flag) 
+               wflush(cp,&cp->cx.datq); else
+               flush(&cp->cx.datq);
+       if (!(cp->c_flags&YGRP)) {
+               flush(&cp->cy.datq);
+       }
+       cp->c_flags = NULL;
+out:
+       if (!flag) {
+               gp = cp->c_group;
+               cp->c_group = NULL;
+               ip = gp->g_inode;
+               if (ip==NULL || (ip->i_mode&IFMT)!=IFMPC) {
+                       printf("chfree on %o\n",ip);
+                       return;
+               }
+               gp->g_chans[cp->c_index] = NULL;
+       }
+}
+
+chclear(cp)
+register struct chan *cp;
+{
+register char *p;
+
+#ifdef CTRACE
+register struct file *fp;
+       fp = cp->c_fy;
+       if (fp) {
+               printf(" count %d on cp %o\n",fp->f_count,cp);
+       }
+#endif
+       p = (char *)&cp->cx.datq;
+       wakeup(p); wakeup(++p); wakeup(++p);
+       p = (char *)&cp->cy.datq;
+       wakeup(p); wakeup(++p); wakeup(++p);
+       return(0);
+}
+
+
+
+flush(q)
+register struct clist *q;
+{
+
+       while(q->c_cc)
+               getc(q);
+}
+
+
+wflush(cp,q)
+register struct chan *cp;
+register struct clist *q;
+{
+register s;
+
+       s = spl6();
+       while(q->c_cc) {
+               if (cp->c_flags & WCLOSE) {
+                       flush(q);
+                       goto out;
+               }
+               cp->c_flags |= WFLUSH;
+               sdata(cp);
+               sleep((caddr_t)q+2,TTOPRI);
+       }
+out:
+       cp->c_flags &= ~WFLUSH;
+       splx(s);
+}
+
+
+scontrol(cp,event,value)
+register struct chan *cp;
+short event,value;
+{
+register struct clist *q;
+int s;
+
+       q = &cp->c_ctlx;
+       s = spl6();
+       putw(event,q);
+       putw(value,q);
+       splx(s);
+       sdata(cp);
+}
+
+sdata(cp)
+register struct chan *cp;
+{
+register struct group *gp;
+register short x;
+register struct group *lgp;
+int s;
+
+       gp = cp->c_group;
+       x = cp->c_index;
+
+       s = spl6();
+       while (gp) {
+               gp->g_datq |= cmask[x];
+               x = gp->g_index;
+               lgp = gp;
+               gp = gp->g_group;
+       }
+       gp =  lgp;
+       splx(s);
+       wakeup((caddr_t)&gp->g_datq);
+}
+
+
+
+struct chan *
+xcp(gp, x)
+register struct group *gp;
+register short x;
+{
+register i;
+
+       i = 0;
+       while (i<NLEVELS && gp->g_state&ISGRP) {
+               gp = (struct group *)gp->g_chans[x&017];
+               x >>= 4;
+       }
+       return((struct chan *)gp);
+}
+
+cpx(cp)
+register struct chan *cp;
+{
+register x;
+register struct group *gp;
+
+       x = cp->c_index;
+       gp = cp->c_group;
+       gp = gp->g_group;
+       while (gp) {
+               x <<= 4;
+               x |= gp->g_index;
+               gp = gp->g_group;
+       }
+       return(x);
+}
+
+
+
+struct chan *
+nextcp(gp)
+register struct group *gp;
+{
+
+       if (gp->g_datq == 0) {
+               gp = NULL;
+               goto out;
+       }
+
+       while (gp != NULL && gp->g_state&ISGRP) {
+               while ( (gp->g_datq & gp->g_rotmask) == 0) {
+                       gp->g_rot++;
+                       gp->g_rot &= 017;
+                       if (gp->g_rot)
+                               gp->g_rotmask <<= 1; else
+                               gp->g_rotmask = 1;
+               }
+               gp = (struct group *)gp->g_chans[gp->g_rot];
+       }
+       if (gp)
+               rmdata(gp);
+out:
+       return((struct chan *)gp);
+}
+
+rmdata(cp)
+register struct chan *cp;
+{
+register struct group *gp;
+register short x;
+
+       gp = cp->c_group;
+       x = cp->c_index;
+
+       while (gp) {
+               gp->g_datq &= ~cmask[x];
+               if (gp->g_datq)
+                       return;
+               x = gp->g_index;
+               gp = gp->g_group;
+       }
+}
+
+
+
+
+
+mcrint(c, tp)
+struct tty *tp;
+{
+}
+
+mcxint(tp)
+struct tty *tp;
+{
+}
+prstuff(s,cc)
+register char *s;
+register cc;
+{
+       while (cc--)
+               printf("%o ",*s++&0377);
+}
diff --git a/usr/src/slowsys/sys/nami.c b/usr/src/slowsys/sys/nami.c
new file mode 100644 (file)
index 0000000..1e0c4e6
--- /dev/null
@@ -0,0 +1,216 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/inode.h"
+#include "../h/mount.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+
+/*
+ * Convert a pathname into a pointer to
+ * an inode. Note that the inode is locked.
+ *
+ * func = function called to get next char of name
+ *     &uchar if name is in user space
+ *     &schar if name is in system space
+ * flag = 0 if name is sought
+ *     1 if name is to be created
+ *     2 if name is to be deleted
+ */
+struct inode *
+namei(func, flag)
+int (*func)();
+{
+       register struct inode *dp;
+       register c;
+       register char *cp;
+       struct buf *bp;
+       int i;
+       dev_t d;
+       off_t eo;
+
+       /*
+        * If name starts with '/' start from
+        * root; otherwise start from current dir.
+        */
+
+       dp = u.u_cdir;
+       if((c=(*func)()) == '/')
+               if ((dp = u.u_rdir) == NULL)
+                       dp = rootdir;
+       iget(dp->i_dev, dp->i_number);
+       while(c == '/')
+               c = (*func)();
+       if(c == '\0' && flag != 0)
+               u.u_error = ENOENT;
+
+cloop:
+       /*
+        * Here dp contains pointer
+        * to last component matched.
+        */
+
+       if(u.u_error)
+               goto out;
+       if(c == '\0')
+               return(dp);
+
+       /*
+        * If there is another component,
+        * Gather up name into
+        * users' dir buffer.
+        */
+
+       cp = &u.u_dbuf[0];
+       while(c != '/' && c != '\0' && u.u_error == 0) {
+               if(cp < &u.u_dbuf[DIRSIZ])
+                       *cp++ = c;
+               c = (*func)();
+       }
+       while(cp < &u.u_dbuf[DIRSIZ])
+               *cp++ = '\0';
+       while(c == '/')
+               c = (*func)();
+
+seloop:
+       /*
+        * dp must be a directory and
+        * must have X permission.
+        */
+
+       if((dp->i_mode&IFMT) != IFDIR)
+               u.u_error = ENOTDIR;
+       access(dp, IEXEC);
+       if(u.u_error)
+               goto out;
+
+       /*
+        * set up to search a directory
+        */
+       u.u_offset = 0;
+       u.u_segflg = 1;
+       eo = 0;
+       bp = NULL;
+
+eloop:
+
+       /*
+        * If at the end of the directory,
+        * the search failed. Report what
+        * is appropriate as per flag.
+        */
+
+       if(u.u_offset >= dp->i_size) {
+               if(bp != NULL)
+                       brelse(bp);
+               if(flag==1 && c=='\0') {
+                       if(access(dp, IWRITE))
+                               goto out;
+                       u.u_pdir = dp;
+                       if(eo)
+                               u.u_offset = eo-sizeof(struct direct);
+                       else
+                               dp->i_flag |= IUPD|ICHG;
+                       return(NULL);
+               }
+               u.u_error = ENOENT;
+               goto out;
+       }
+
+       /*
+        * If offset is on a block boundary,
+        * read the next directory block.
+        * Release previous if it exists.
+        */
+
+       if((u.u_offset&BMASK) == 0) {
+               if(bp != NULL)
+                       brelse(bp);
+               bp = bread(dp->i_dev,
+                       bmap(dp, (daddr_t)(u.u_offset>>BSHIFT), B_READ));
+               if (bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       goto out;
+               }
+       }
+
+       /*
+        * Note first empty directory slot
+        * in eo for possible creat.
+        * String compare the directory entry
+        * and the current component.
+        * If they do not match, go back to eloop.
+        */
+
+       bcopy(bp->b_un.b_addr+(u.u_offset&BMASK), (caddr_t)&u.u_dent,
+               sizeof(struct direct));
+       u.u_offset += sizeof(struct direct);
+       if(u.u_dent.d_ino == 0) {
+               if(eo == 0)
+                       eo = u.u_offset;
+               goto eloop;
+       }
+       for(i=0; i<DIRSIZ; i++)
+               if(u.u_dbuf[i] != u.u_dent.d_name[i])
+                       goto eloop;
+
+       /*
+        * Here a component matched in a directory.
+        * If there is more pathname, go back to
+        * cloop, otherwise return.
+        */
+
+       if(bp != NULL)
+               brelse(bp);
+       if(flag==2 && c=='\0') {
+               if(access(dp, IWRITE))
+                       goto out;
+               return(dp);
+       }
+       d = dp->i_dev;
+       if(u.u_dent.d_ino == ROOTINO)
+       if(dp->i_number == ROOTINO)
+       if(u.u_dent.d_name[1] == '.')
+               for(i=1; i<NMOUNT; i++)
+                       if(mount[i].m_bufp != NULL)
+                       if(mount[i].m_dev == d) {
+                               iput(dp);
+                               dp = mount[i].m_inodp;
+                               dp->i_count++;
+                               plock(dp);
+                               goto seloop;
+                       }
+       iput(dp);
+       dp = iget(d, u.u_dent.d_ino);
+       if(dp == NULL)
+               return(NULL);
+       goto cloop;
+
+out:
+       iput(dp);
+       return(NULL);
+}
+
+/*
+ * Return the next character from the
+ * kernel string pointed at by dirp.
+ */
+schar()
+{
+
+       return(*u.u_dirp++ & 0377);
+}
+
+/*
+ * Return the next character from the
+ * user string pointed at by dirp.
+ */
+uchar()
+{
+       register c;
+
+       c = fubyte(u.u_dirp++);
+       if(c == -1)
+               u.u_error = EFAULT;
+       return(c);
+}
diff --git a/usr/src/slowsys/sys/partab.c b/usr/src/slowsys/sys/partab.c
new file mode 100644 (file)
index 0000000..44628c4
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ */
+
+char partab[] = {
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0202,0004,0003,0201,0005,0206,0201,0001,
+       0201,0001,0001,0201,0001,0201,0201,0001,
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0201
+};
diff --git a/usr/src/slowsys/sys/pipe.c b/usr/src/slowsys/sys/pipe.c
new file mode 100644 (file)
index 0000000..1ca26ba
--- /dev/null
@@ -0,0 +1,216 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/reg.h"
+
+/*
+ * Max allowable buffering per pipe.
+ * This is also the max size of the
+ * file created to implement the pipe.
+ * If this size is bigger than 5120,
+ * pipes will be implemented with large
+ * files, which is probably not good.
+ */
+#define        PIPSIZ  4096
+
+/*
+ * The sys-pipe entry.
+ * Allocate an inode on the root device.
+ * Allocate 2 file structures.
+ * Put it all together with flags.
+ */
+pipe()
+{
+       register struct inode *ip;
+       register struct file *rf, *wf;
+       int r;
+
+       ip = ialloc(pipedev);
+       if(ip == NULL)
+               return;
+       rf = falloc();
+       if(rf == NULL) {
+               iput(ip);
+               return;
+       }
+       r = u.u_r.r_val1;
+       wf = falloc();
+       if(wf == NULL) {
+               rf->f_count = 0;
+               u.u_ofile[r] = NULL;
+               iput(ip);
+               return;
+       }
+       u.u_r.r_val2 = u.u_r.r_val1;
+       u.u_r.r_val1 = r;
+       wf->f_flag = FWRITE|FPIPE;
+       wf->f_inode = ip;
+       rf->f_flag = FREAD|FPIPE;
+       rf->f_inode = ip;
+       ip->i_count = 2;
+       ip->i_mode = IFREG;
+       ip->i_flag = IACC|IUPD|ICHG;
+}
+
+/*
+ * Read call directed to a pipe.
+ */
+readp(fp)
+register struct file *fp;
+{
+       register struct inode *ip;
+
+       ip = fp->f_inode;
+
+loop:
+       /*
+        * Very conservative locking.
+        */
+
+       plock(ip);
+       /*
+        * If nothing in the pipe, wait.
+        */
+       if (ip->i_size == 0) {
+               /*
+                * If there are not both reader and
+                * writer active, return without
+                * satisfying read.
+                */
+               prele(ip);
+               if(ip->i_count < 2)
+                       return;
+               ip->i_mode |= IREAD;
+               sleep((caddr_t)ip+2, PPIPE);
+               goto loop;
+       }
+
+       /*
+        * Read and return
+        */
+
+       u.u_offset = fp->f_un.f_offset;
+       readi(ip);
+       fp->f_un.f_offset = u.u_offset;
+       /*
+        * If reader has caught up with writer, reset
+        * offset and size to 0.
+        */
+       if (fp->f_un.f_offset == ip->i_size) {
+               fp->f_un.f_offset = 0;
+               ip->i_size = 0;
+               if(ip->i_mode & IWRITE) {
+                       ip->i_mode &= ~IWRITE;
+                       wakeup((caddr_t)ip+1);
+               }
+       }
+       prele(ip);
+}
+
+/*
+ * Write call directed to a pipe.
+ */
+writep(fp)
+register struct file *fp;
+{
+       register c;
+       register struct inode *ip;
+
+       ip = fp->f_inode;
+       c = u.u_count;
+
+loop:
+
+       /*
+        * If all done, return.
+        */
+
+       plock(ip);
+       if(c == 0) {
+               prele(ip);
+               u.u_count = 0;
+               return;
+       }
+
+       /*
+        * If there are not both read and
+        * write sides of the pipe active,
+        * return error and signal too.
+        */
+
+       if(ip->i_count < 2) {
+               prele(ip);
+               u.u_error = EPIPE;
+               psignal(u.u_procp, SIGPIPE);
+               return;
+       }
+
+       /*
+        * If the pipe is full,
+        * wait for reads to deplete
+        * and truncate it.
+        */
+
+       if(ip->i_size >= PIPSIZ) {
+               ip->i_mode |= IWRITE;
+               prele(ip);
+               sleep((caddr_t)ip+1, PPIPE);
+               goto loop;
+       }
+
+       /*
+        * Write what is possible and
+        * loop back.
+        * If writing less than PIPSIZ, it always goes.
+        * One can therefore get a file > PIPSIZ if write
+        * sizes do not divide PIPSIZ.
+        */
+
+       u.u_offset = ip->i_size;
+       u.u_count = min((unsigned)c, (unsigned)PIPSIZ);
+       c -= u.u_count;
+       writei(ip);
+       prele(ip);
+       if(ip->i_mode&IREAD) {
+               ip->i_mode &= ~IREAD;
+               wakeup((caddr_t)ip+2);
+       }
+       goto loop;
+}
+
+/*
+ * Lock a pipe.
+ * If its already locked,
+ * set the WANT bit and sleep.
+ */
+plock(ip)
+register struct inode *ip;
+{
+
+       while(ip->i_flag&ILOCK) {
+               ip->i_flag |= IWANT;
+               sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCK;
+}
+
+/*
+ * Unlock a pipe.
+ * If WANT bit is on,
+ * wakeup.
+ * This routine is also used
+ * to unlock inodes in general.
+ */
+prele(ip)
+register struct inode *ip;
+{
+
+       ip->i_flag &= ~ILOCK;
+       if(ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
diff --git a/usr/src/slowsys/sys/prf.c b/usr/src/slowsys/sys/prf.c
new file mode 100644 (file)
index 0000000..1b12141
--- /dev/null
@@ -0,0 +1,115 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/seg.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+
+/*
+ * In case console is off,
+ * panicstr contains argument to last
+ * call to panic.
+ */
+
+char   *panicstr;
+
+/*
+ * Scaled down version of C Library printf.
+ * Only %s %u %d (==%u) %o %x %D are recognized.
+ * Used to print diagnostic information
+ * directly on console tty.
+ * Since it is not interrupt driven,
+ * all system activities are pretty much
+ * suspended.
+ * Printf should not be used for chit-chat.
+ */
+/* VARARGS */
+printf(fmt, x1)
+register char *fmt;
+unsigned x1;
+{
+       register c;
+       register unsigned int *adx;
+       char *s;
+
+       adx = &x1;
+loop:
+       while((c = *fmt++) != '%') {
+               if(c == '\0')
+                       return;
+               putchar(c);
+       }
+       c = *fmt++;
+       if(c == 'd' || c == 'u' || c == 'o' || c == 'x')
+               printn((long)*adx, c=='o'? 8: (c=='x'? 16:10));
+       else if(c == 's') {
+               s = (char *)*adx;
+               while(c = *s++)
+                       putchar(c);
+       } else if (c == 'D') {
+               printn(*(long *)adx, 10);
+               adx += (sizeof(long) / sizeof(int)) - 1;
+       }
+       adx++;
+       goto loop;
+}
+
+/*
+ * Print an unsigned integer in base b.
+ */
+printn(n, b)
+long n;
+{
+       register long a;
+
+       if (n<0) {      /* shouldn't happen */
+               putchar('-');
+               n = -n;
+       }
+       if(a = n/b)
+               printn(a, b);
+       putchar("0123456789ABCDEF"[(int)(n%b)]);
+}
+
+/*
+ * Panic is called on unresolvable
+ * fatal errors.
+ * It syncs, prints "panic: mesg" and
+ * then loops.
+ */
+panic(s)
+char *s;
+{
+       panicstr = s;
+       update();
+       printf("panic: %s\n", s);
+       for(;;)
+               idle();
+}
+
+/*
+ * prdev prints a warning message of the
+ * form "mesg on dev x/y".
+ * x and y are the major and minor parts of
+ * the device argument.
+ */
+prdev(str, dev)
+char *str;
+dev_t dev;
+{
+
+       printf("%s on dev %u/%u\n", str, major(dev), minor(dev));
+}
+
+/*
+ * deverr prints a diagnostic from
+ * a device driver.
+ * It prints the device, block number,
+ * and an octal word (usually some error
+ * status register) passed as argument.
+ */
+deverror(bp, o1, o2)
+register struct buf *bp;
+{
+
+       prdev("err", bp->b_dev);
+}
diff --git a/usr/src/slowsys/sys/prim.c b/usr/src/slowsys/sys/prim.c
new file mode 100644 (file)
index 0000000..43d5997
--- /dev/null
@@ -0,0 +1,136 @@
+#include "../h/param.h"
+#include "../h/tty.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+
+struct cblock {
+       struct cblock *c_next;
+       char    c_info[CBSIZE];
+};
+
+struct cblock  cfree[NCLIST];
+struct cblock  *cfreelist;
+
+/*
+ * Character list get/put
+ */
+getc(p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register int c, s;
+
+       s = spl6();
+       if (p->c_cc <= 0) {
+               c = -1;
+               p->c_cc = 0;
+               p->c_cf = p->c_cl = NULL;
+       } else {
+               c = *p->c_cf++ & 0377;
+               if (--p->c_cc<=0) {
+                       bp = (struct cblock *)(p->c_cf-1);
+                       bp = (struct cblock *) ((int)bp & ~CROUND);
+                       p->c_cf = NULL;
+                       p->c_cl = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               } else if (((int)p->c_cf & CROUND) == 0){
+                       bp = (struct cblock *)(p->c_cf);
+                       bp--;
+                       p->c_cf = bp->c_next->c_info;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               }
+       }
+       splx(s);
+       return(c);
+}
+
+putc(c, p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register char *cp;
+       register s;
+
+       s = spl6();
+       if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
+               if ((bp = cfreelist) == NULL) {
+                       splx(s);
+                       return(-1);
+               }
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               p->c_cf = cp = bp->c_info;
+       } else if (((int)cp & CROUND) == 0) {
+               bp = (struct cblock *)cp - 1;
+               if ((bp->c_next = cfreelist) == NULL) {
+                       splx(s);
+                       return(-1);
+               }
+               bp = bp->c_next;
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               cp = bp->c_info;
+       }
+       *cp++ = c;
+       p->c_cc++;
+       p->c_cl = cp;
+       splx(s);
+       return(0);
+}
+
+/*
+ * Initialize clist by freeing all character blocks, then count
+ * number of character devices. (Once-only routine)
+ */
+cinit()
+{
+       register int ccp;
+       register struct cblock *cp;
+       register struct cdevsw *cdp;
+
+       ccp = (int)cfree;
+       ccp = (ccp+CROUND) & ~CROUND;
+       for(cp=(struct cblock *)ccp; cp <= &cfree[NCLIST-1]; cp++) {
+               cp->c_next = cfreelist;
+               cfreelist = cp;
+       }
+       ccp = 0;
+       for(cdp = cdevsw; cdp->d_open; cdp++)
+               ccp++;
+       nchrdev = ccp;
+}
+
+
+/*
+ * integer (2-byte) get/put
+ * using clists
+ */
+getw(p)
+register struct clist *p;
+{
+       register int s;
+
+       if (p->c_cc <= 1)
+               return(-1);
+       s = getc(p);
+       return(s | (getc(p)<<8));
+}
+
+putw(c, p)
+register struct clist *p;
+{
+       register s;
+
+       s = spl6();
+       if (cfreelist==NULL) {
+               splx(s);
+               return(-1);
+       }
+       putc(c, p);
+       putc(c>>8, p);
+       splx(s);
+       return(0);
+}
diff --git a/usr/src/slowsys/sys/rdwri.c b/usr/src/slowsys/sys/rdwri.c
new file mode 100644 (file)
index 0000000..acb8670
--- /dev/null
@@ -0,0 +1,197 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/inode.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+#include "../h/conf.h"
+
+/*
+ * Read the file corresponding to
+ * the inode pointed at by the argument.
+ * The actual read arguments are found
+ * in the variables:
+ *     u_base          core address for destination
+ *     u_offset        byte offset in file
+ *     u_count         number of bytes to read
+ *     u_segflg        read to kernel/user/user I
+ */
+readi(ip)
+register struct inode *ip;
+{
+       struct buf *bp;
+       dev_t dev;
+       daddr_t lbn, bn;
+       off_t diff;
+       register on, n;
+       register type;
+       extern int mem_no;
+
+       if(u.u_count == 0)
+               return;
+       dev = (dev_t)ip->i_un.i_rdev;
+       if(u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)) ) {
+               u.u_error = EINVAL;
+               return;
+       }
+       ip->i_flag |= IACC;
+       type = ip->i_mode&IFMT;
+       if (type==IFCHR || type==IFMPC) {
+               (*cdevsw[major(dev)].d_read)(dev);
+               return;
+       }
+
+       do {
+               lbn = bn = u.u_offset >> BSHIFT;
+               on = u.u_offset & BMASK;
+               n = min((unsigned)(BSIZE-on), u.u_count);
+               if(type!=IFBLK && type!=IFMPB) {
+                       diff = ip->i_size - u.u_offset;
+                       if(diff <= 0)
+                               return;
+                       if(diff < n)
+                               n = diff;
+                       bn = bmap(ip, bn, B_READ);
+                       if(u.u_error)
+                               return;
+                       dev = ip->i_dev;
+               } else
+                       rablock = bn+1;
+               if ((long)bn<0) {
+                       bp = geteblk();
+                       clrbuf(bp);
+               } else if (ip->i_un.i_lastr+1 == lbn)
+                       bp = breada(dev, bn, rablock);
+               else
+                       bp = bread(dev, bn);
+               ip->i_un.i_lastr = lbn;
+               n = min((unsigned)n, BSIZE-bp->b_resid);
+               if (n!=0)
+                       {
+                       iomove(bp->b_un.b_addr+on, n, B_READ);
+                       }
+               brelse(bp);
+       } while(u.u_error==0 && u.u_count!=0 && n>0);
+}
+
+/*
+ * Write the file corresponding to
+ * the inode pointed at by the argument.
+ * The actual write arguments are found
+ * in the variables:
+ *     u_base          core address for source
+ *     u_offset        byte offset in file
+ *     u_count         number of bytes to write
+ *     u_segflg        write to kernel/user/user I
+ */
+writei(ip)
+register struct inode *ip;
+{
+       struct buf *bp;
+       dev_t dev;
+       daddr_t bn;
+       register n, on;
+       register type;
+       extern int mem_no;
+
+       dev = (dev_t)ip->i_un.i_rdev;
+       if(u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)) ) {
+               u.u_error = EINVAL;
+               return;
+       }
+       type = ip->i_mode&IFMT;
+       if (type==IFCHR || type==IFMPC) {
+               ip->i_flag |= IUPD|ICHG;
+               (*cdevsw[major(dev)].d_write)(dev);
+               return;
+       }
+       if (u.u_count == 0)
+               return;
+
+       do {
+               bn = u.u_offset >> BSHIFT;
+               on = u.u_offset & BMASK;
+               n = min((unsigned)BSIZE-on, u.u_count);
+               if(type!=IFBLK && type!=IFMPB) {
+                       bn = bmap(ip, bn, B_WRITE);
+                       if((long)bn<0)
+                               return;
+                       dev = ip->i_dev;
+               }
+               if(n == BSIZE) 
+                       bp = getblk(dev, bn);
+               else
+                       bp = bread(dev, bn);
+               iomove(bp->b_un.b_addr+on, n, B_WRITE);
+               if(u.u_error != 0)
+                       brelse(bp);
+               else
+                       bdwrite(bp);
+               if(u.u_offset > ip->i_size &&
+                       (type==IFDIR || type==IFREG))
+                        ip->i_size = u.u_offset;
+               ip->i_flag |= IUPD|ICHG;
+       } while(u.u_error==0 && u.u_count!=0);
+}
+
+/*
+ * Return the logical maximum
+ * of the 2 arguments.
+ */
+max(a, b)
+unsigned a, b;
+{
+
+       if(a > b)
+               return(a);
+       return(b);
+}
+
+/*
+ * Return the logical minimum
+ * of the 2 arguments.
+ */
+min(a, b)
+unsigned a, b;
+{
+
+       if(a < b)
+               return(a);
+       return(b);
+}
+
+/*
+ * Move n bytes at byte location
+ * &bp->b_un.b_addr[o] to/from (flag) the
+ * user/kernel (u.segflg) area starting at u.base.
+ * Update all the arguments by the number
+ * of bytes moved.
+ */
+iomove(cp, n, flag)
+register caddr_t cp;
+register n;
+{
+       register t;
+
+       if (n==0)
+               return;
+       if(u.u_segflg != 1)  {
+               if (flag==B_WRITE)
+                       t = copyin(u.u_base, (caddr_t)cp, n);
+               else
+                       t = copyout((caddr_t)cp, u.u_base, n);
+               if (t) {
+                       u.u_error = EFAULT;
+                       return;
+               }
+       }
+       else
+               if (flag == B_WRITE)
+                       bcopy(u.u_base,(caddr_t)cp,n);
+               else
+                       bcopy((caddr_t)cp,u.u_base,n);
+       u.u_base += n;
+       u.u_offset += n;
+       u.u_count -= n;
+       return;
+}
diff --git a/usr/src/slowsys/sys/slp.c b/usr/src/slowsys/sys/slp.c
new file mode 100644 (file)
index 0000000..2c231cd
--- /dev/null
@@ -0,0 +1,547 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/text.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+#include "../h/buf.h"
+
+/*
+ * Give up the processor till a wakeup occurs
+ * on chan, at which time the process
+ * enters the scheduling queue at priority pri.
+ * The most important effect of pri is that when
+ * pri<=PZERO a signal cannot disturb the sleep;
+ * if pri>PZERO signals will be processed.
+ * Callers of this routine must be prepared for
+ * premature return, and check that the reason for
+ * sleeping has gone away.
+ */
+sleep(chan, pri)
+caddr_t chan;
+{
+       register struct proc *rp;
+       register s;
+
+       rp = u.u_procp;
+       s = spl6();
+       rp->p_stat = SSLEEP;
+       rp->p_wchan = chan;
+       rp->p_pri = pri;
+       if(pri > PZERO) {
+               if(issig()) {
+                       rp->p_wchan = 0;
+                       rp->p_stat = SRUN;
+                       spl0();
+                       goto psig;
+               }
+               spl0();
+               if(runin != 0) {
+                       runin = 0;
+                       wakeup((caddr_t)&runin);
+               }
+               swtch();
+               if(issig())
+                       goto psig;
+       } else {
+               spl0();
+               swtch();
+       }
+       splx(s);
+       return;
+
+       /*
+        * If priority was low (>PZERO) and
+        * there has been a signal,
+        * execute non-local goto to
+        * the qsav location.
+        * (see trap1/trap.c)
+        */
+psig:
+       resume(u.u_procp->p_addr, u.u_qsav);
+}
+
+/*
+ * Wake up all processes sleeping on chan.
+ */
+wakeup(chan)
+register caddr_t chan;
+{
+       register struct proc *p;
+       register i;
+       int s;
+
+       p = &proc[0];
+       i = NPROC;
+       do {
+               if(p->p_wchan==chan && p->p_stat!=SZOMB) {
+                       /*
+                        * this code looks dumb, but
+                        * there is a possible race due
+                        * to interrupts.
+                        */
+                       s = spl6();
+                       if(p->p_wchan == chan)
+                               setrun(p);
+                       splx(s);
+               }
+               p++;
+       } while(--i);
+}
+
+/*
+ * when you are sure that it
+ * is impossible to get the
+ * 'proc on q' diagnostic, the
+ * diagnostic loop can be removed.
+ */
+setrq(p)
+struct proc *p;
+{
+       register struct proc *q;
+       register s;
+
+       s = spl6();
+       for(q=runq; q!=NULL; q=q->p_link)
+               if(q == p) {
+                       printf("proc on q\n");
+                       goto out;
+               }
+       p->p_link = runq;
+       runq = p;
+out:
+       splx(s);
+}
+
+/*
+ * Set the process running;
+ * arrange for it to be swapped in if necessary.
+ */
+setrun(p)
+register struct proc *p;
+{
+
+       if (p->p_stat==0 || p->p_stat==SZOMB)
+               panic("Running a dead proc");
+       p->p_wchan = 0;
+       p->p_stat = SRUN;
+       setrq(p);
+       if(p->p_pri < curpri)
+               runrun++;
+       if(runout != 0 && (p->p_flag&SLOAD) == 0) {
+               runout = 0;
+               wakeup((caddr_t)&runout);
+       }
+}
+
+/*
+ * Set user priority.
+ * The rescheduling flag (runrun)
+ * is set if the priority is better
+ * than the currently running process.
+ */
+setpri(pp)
+register struct proc *pp;
+{
+       register p;
+
+       p = (pp->p_cpu & 0377)/16;
+       p += PUSER + pp->p_nice - NZERO;
+       if(p > 127)
+               p = 127;
+       if(p < curpri)
+               runrun++;
+       pp->p_pri = p;
+       return(p);
+}
+
+/*
+ * The main loop of the scheduling (swapping)
+ * process.
+ * The basic idea is:
+ *  see if anyone wants to be swapped in;
+ *  swap out processes until there is room;
+ *  swap him in;
+ *  repeat.
+ * The runout flag is set whenever someone is swapped out.
+ * Sched sleeps on it awaiting work.
+ *
+ * Sched sleeps on runin whenever it cannot find enough
+ * core (by swapping out or otherwise) to fit the
+ * selected swapped process.  It is awakened when the
+ * core situation changes and in any case once per second.
+ */
+sched()
+{
+       register struct proc *rp, *p;
+       register outage, inage;
+       int maxsize;
+
+       /*
+        * find user to swap in;
+        * of users ready, select one out longest
+        */
+
+loop:
+       spl6();
+       outage = -20000;
+       for (rp = &proc[0]; rp < &proc[NPROC]; rp++)
+       if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
+           rp->p_time - (rp->p_nice-NZERO)*8 > outage) {
+               p = rp;
+               outage = rp->p_time - (rp->p_nice-NZERO)*8;
+       }
+       /*
+        * If there is no one there, wait.
+        */
+       if (outage == -20000) {
+               runout++;
+               sleep((caddr_t)&runout, PSWP);
+               goto loop;
+       }
+       spl0();
+
+       /*
+        * See if there is core for that process;
+        * if so, swap it in.
+        */
+
+       if (swapin(p))
+               goto loop;
+
+       /*
+        * none found.
+        * look around for core.
+        * Select the largest of those sleeping
+        * at bad priority; if none, select the oldest.
+        */
+
+       spl6();
+       p = NULL;
+       maxsize = -1;
+       inage = -1;
+       for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {
+               if (rp->p_stat==SZOMB
+                || (rp->p_flag&(SSYS|SLOCK|SULOCK|SLOAD))!=SLOAD)
+                       continue;
+               if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
+                       continue;
+               if (rp->p_stat==SSLEEP&&rp->p_pri>=PZERO || rp->p_stat==SSTOP) {
+                       if (maxsize < rp->p_size) {
+                               p = rp;
+                               maxsize = rp->p_size;
+                       }
+               } else if (maxsize<0 && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) {
+                       if (rp->p_time+rp->p_nice-NZERO > inage) {
+                               p = rp;
+                               inage = rp->p_time+rp->p_nice-NZERO;
+                       }
+               }
+       }
+       spl0();
+       /*
+        * Swap found user out if sleeping at bad pri,
+        * or if he has spent at least 2 seconds in core and
+        * the swapped-out process has spent at least 3 seconds out.
+        * Otherwise wait a bit and try again.
+        */
+       if (maxsize>=0 || (outage>=3 && inage>=2)) {
+               p->p_flag &= ~SLOAD;
+               xswap(p, 1, 0);
+               goto loop;
+       }
+       spl6();
+       runin++;
+       sleep((caddr_t)&runin, PSWP);
+       goto loop;
+}
+
+/*
+ * Swap a process in.
+ * Allocate data and possible text separately.
+ * It would be better to do largest first.
+ */
+swapin(p)
+register struct proc *p;
+{
+       register struct text *xp;
+       register int a;
+       int x;
+
+       if ((a = malloc(coremap, p->p_size)) == NULL)
+               return(0);
+       if (xp = p->p_textp) {
+               xlock(xp);
+               if (xp->x_ccount==0) {
+                       if ((x = malloc(coremap, xp->x_size)) == NULL) {
+                               xunlock(xp);
+                               mfree(coremap, p->p_size, a);
+                               return(0);
+                       }
+                       xp->x_caddr = x;
+                       if ((xp->x_flag&XLOAD)==0)
+                               swap(xp->x_daddr,x,xp->x_size,B_READ);
+               }
+               xp->x_ccount++;
+               xunlock(xp);
+       }
+       swap(p->p_addr, a, p->p_size, B_READ);
+       mfree(swapmap, ctod(p->p_size), p->p_addr);
+       p->p_addr = a;
+       p->p_flag |= SLOAD;
+       p->p_time = 0;
+       return(1);
+}
+
+/*
+ * put the current process on
+ * the Q of running processes and
+ * call the scheduler.
+ */
+qswtch()
+{
+
+       setrq(u.u_procp);
+       swtch();
+}
+
+/*
+ * This routine is called to reschedule the CPU.
+ * if the calling process is not in RUN state,
+ * arrangements for it to restart must have
+ * been made elsewhere, usually by calling via sleep.
+ * There is a race here. A process may become
+ * ready after it has been examined.
+ * In this case, idle() will be called and
+ * will return in at most 1HZ time.
+ * i.e. its not worth putting an spl() in.
+ */
+swtch()
+{
+       register n;
+       register struct proc *p, *q, *pp, *pq;
+
+       /*
+        * If not the idle process, resume the idle process.
+        */
+       if (u.u_procp != &proc[0]) {
+               if (save(u.u_rsav)) {
+                       sureg();
+                       return;
+               }
+               resume(proc[0].p_addr, u.u_qsav);
+       }
+       /*
+        * The first save returns nonzero when proc 0 is resumed
+        * by another process (above); then the second is not done
+        * and the process-search loop is entered.
+        *
+        * The first save returns 0 when swtch is called in proc 0
+        * from sched().  The second save returns 0 immediately, so
+        * in this case too the process-search loop is entered.
+        * Thus when proc 0 is awakened by being made runnable, it will
+        * find itself and resume itself at rsav, and return to sched().
+        */
+       if (save(u.u_qsav)==0 && save(u.u_rsav))
+               return;
+loop:
+       spl6();
+       runrun = 0;
+       pp = NULL;
+       q = NULL;
+       n = 128;
+       /*
+        * Search for highest-priority runnable process
+        */
+       for(p=runq; p!=NULL; p=p->p_link) {
+               if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {
+                       if(p->p_pri < n) {
+                               pp = p;
+                               pq = q;
+                               n = p->p_pri;
+                       }
+               }
+               q = p;
+       }
+       /*
+        * If no process is runnable, idle.
+        */
+       p = pp;
+       if(p == NULL) {
+               idle();
+               goto loop;
+       }
+       q = pq;
+       if(q == NULL)
+               runq = p->p_link;
+       else
+               q->p_link = p->p_link;
+       curpri = n;
+       spl0();
+       /*
+        * The rsav (ssav) contents are interpreted in the new address space
+        */
+       n = p->p_flag&SSWAP;
+       p->p_flag &= ~SSWAP;
+       resume(p->p_addr, n? u.u_ssav: u.u_rsav);
+}
+
+/*
+ * Create a new process-- the internal version of
+ * sys fork.
+ * It returns 1 in the new process, 0 in the old.
+ */
+newproc()
+{
+       int a1, a2;
+       struct proc *p, *up;
+       register struct proc *rpp, *rip;
+       register n;
+
+       p = NULL;
+       /*
+        * First, just locate a slot for a process
+        * and copy the useful info from this process into it.
+        * The panic "cannot happen" because fork has already
+        * checked for the existence of a slot.
+        */
+retry:
+       mpid++;
+       if(mpid >= 30000) {
+               mpid = 0;
+               goto retry;
+       }
+       for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {
+               if(rpp->p_stat == NULL && p==NULL)
+                       p = rpp;
+               if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
+                       goto retry;
+       }
+       if ((rpp = p)==NULL)
+               panic("no procs");
+
+       /*
+        * make proc entry for new proc
+        */
+
+       rip = u.u_procp;
+       up = rip;
+       rpp->p_stat = SRUN;
+       rpp->p_clktim = 0;
+       rpp->p_flag = SLOAD;
+       rpp->p_uid = rip->p_uid;
+       rpp->p_pgrp = rip->p_pgrp;
+       rpp->p_nice = rip->p_nice;
+       rpp->p_textp = rip->p_textp;
+       rpp->p_pid = mpid;
+       rpp->p_ppid = rip->p_pid;
+       rpp->p_time = 0;
+       rpp->p_cpu = 0;
+
+       /*
+        * make duplicate entries
+        * where needed
+        */
+
+       for(n=0; n<NOFILE; n++)
+               if(u.u_ofile[n] != NULL)
+                       u.u_ofile[n]->f_count++;
+       if(up->p_textp != NULL) {
+               up->p_textp->x_count++;
+               up->p_textp->x_ccount++;
+       }
+       u.u_cdir->i_count++;
+       if (u.u_rdir)
+               u.u_rdir->i_count++;
+       /*
+        * Partially simulate the environment
+        * of the new process so that when it is actually
+        * created (by copying) it will look right.
+        */
+       rpp = p;
+       u.u_procp = rpp;
+       rip = up;
+       n = rip->p_size;
+       a1 = rip->p_addr;
+       rpp->p_size = n;
+       /*
+        * When the resume is executed for the new process,
+        * here's where it will resume.
+        */
+       if (save(u.u_ssav)) {
+               sureg();
+               return(1);
+       }
+       a2 = malloc(coremap, n);
+       /*
+        * If there is not enough core for the
+        * new process, swap out the current process to generate the
+        * copy.
+        */
+       if(a2 == NULL) {
+               rip->p_stat = SIDL;
+               rpp->p_addr = a1;
+               xswap(rpp, 0, 0);
+               rip->p_stat = SRUN;
+       } else {
+               /*
+                * There is core, so just copy.
+                */
+               rpp->p_addr = a2;
+               while(n--)
+                       copyseg(a1++, a2++);
+       }
+       u.u_procp = rip;
+       setrq(rpp);
+       rpp->p_flag |= SSWAP;
+       return(0);
+}
+
+/*
+ * Change the size of the data+stack regions of the process.
+ * If the size is shrinking, it's easy-- just release the extra core.
+ * If it's growing, and there is core, just allocate it
+ * and copy the image, taking care to reset registers to account
+ * for the fact that the system's stack has moved.
+ * If there is no core, arrange for the process to be swapped
+ * out after adjusting the size requirement-- when it comes
+ * in, enough core will be allocated.
+ *
+ * After the expansion, the caller will take care of copying
+ * the user's stack towards or away from the data area.
+ */
+expand(newsize)
+{
+       register i, n;
+       register struct proc *p;
+       register a1, a2;
+
+       p = u.u_procp;
+       n = p->p_size;
+       p->p_size = newsize;
+       a1 = p->p_addr;
+       if(n >= newsize) {
+               mfree(coremap, n-newsize, a1+newsize);
+               return;
+       }
+       if (save(u.u_ssav)) {
+               sureg();
+               return;
+       }
+       a2 = malloc(coremap, newsize);
+       if(a2 == NULL) {
+               xswap(p, 1, n);
+               p->p_flag |= SSWAP;
+               qswtch();
+               /* no return */
+       }
+       p->p_addr = a2;
+       for(i=0; i<n; i++)
+               copyseg(a1+i, a2+i);
+       mfree(coremap, n, a1);
+       resume(a2, u.u_ssav);
+}
diff --git a/usr/src/slowsys/sys/subr.c b/usr/src/slowsys/sys/subr.c
new file mode 100644 (file)
index 0000000..23958ba
--- /dev/null
@@ -0,0 +1,188 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/inode.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/buf.h"
+
+/*
+ * Bmap defines the structure of file system storage
+ * by returning the physical block number on a device given the
+ * inode and the logical block number in a file.
+ * When convenient, it also leaves the physical
+ * block number of the next block of the file in rablock
+ * for use in read-ahead.
+ */
+daddr_t
+bmap(ip, bn, rwflg)
+register struct inode *ip;
+daddr_t bn;
+{
+       register i;
+       struct buf *bp, *nbp;
+       int j, sh;
+       daddr_t nb, *bap;
+       dev_t dev;
+
+       if(bn < 0) {
+               u.u_error = EFBIG;
+               return((daddr_t)0);
+       }
+       dev = ip->i_dev;
+       rablock = 0;
+
+       /*
+        * blocks 0..NADDR-4 are direct blocks
+        */
+       if(bn < NADDR-3) {
+               i = bn;
+               nb = ip->i_un.i_addr[i];
+               if(nb == 0) {
+                       if(rwflg==B_READ || (bp = alloc(dev))==NULL)
+                               return((daddr_t)-1);
+                       nb = bp->b_blkno;
+                       bdwrite(bp);
+                       ip->i_un.i_addr[i] = nb;
+                       ip->i_flag |= IUPD|ICHG;
+               }
+               if(i < NADDR-4)
+                       rablock = ip->i_un.i_addr[i+1];
+               return(nb);
+       }
+
+       /*
+        * addresses NADDR-3, NADDR-2, and NADDR-1
+        * have single, double, triple indirect blocks.
+        * the first step is to determine
+        * how many levels of indirection.
+        */
+       sh = 0;
+       nb = 1;
+       bn -= NADDR-3;
+       for(j=3; j>0; j--) {
+               sh += NSHIFT;
+               nb <<= NSHIFT;
+               if(bn < nb)
+                       break;
+               bn -= nb;
+       }
+       if(j == 0) {
+               u.u_error = EFBIG;
+               return((daddr_t)0);
+       }
+
+       /*
+        * fetch the address from the inode
+        */
+       nb = ip->i_un.i_addr[NADDR-j];
+       if(nb == 0) {
+               if(rwflg==B_READ || (bp = alloc(dev))==NULL)
+                       return((daddr_t)-1);
+               nb = bp->b_blkno;
+               bdwrite(bp);
+               ip->i_un.i_addr[NADDR-j] = nb;
+               ip->i_flag |= IUPD|ICHG;
+       }
+
+       /*
+        * fetch through the indirect blocks
+        */
+       for(; j<=3; j++) {
+               bp = bread(dev, nb);
+               if(bp->b_flags & B_ERROR) {
+                       brelse(bp);
+                       return((daddr_t)0);
+               }
+               bap = bp->b_un.b_daddr;
+               sh -= NSHIFT;
+               i = (bn>>sh) & NMASK;
+               nb = bap[i];
+               if(nb == 0) {
+                       if(rwflg==B_READ || (nbp = alloc(dev))==NULL) {
+                               brelse(bp);
+                               return((daddr_t)-1);
+                       }
+                       nb = nbp->b_blkno;
+                       bdwrite(nbp);
+                       bap[i] = nb;
+                       bdwrite(bp);
+               } else
+                       brelse(bp);
+       }
+
+       /*
+        * calculate read-ahead.
+        */
+       if(i < NINDIR-1)
+               rablock = bap[i+1];
+       return(nb);
+}
+
+/*
+ * Pass back  c  to the user at his location u_base;
+ * update u_base, u_count, and u_offset.  Return -1
+ * on the last character of the user's read.
+ * u_base is in the user address space unless u_segflg is set.
+ */
+passc(c)
+register c;
+{
+       register id;
+
+       if((id = u.u_segflg) == 1)
+               *u.u_base = c;
+       else
+               if(id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
+                       u.u_error = EFAULT;
+                       return(-1);
+               }
+       u.u_count--;
+       u.u_offset++;
+       u.u_base++;
+       return(u.u_count == 0? -1: 0);
+}
+
+/*
+ * Pick up and return the next character from the user's
+ * write call at location u_base;
+ * update u_base, u_count, and u_offset.  Return -1
+ * when u_count is exhausted.  u_base is in the user's
+ * address space unless u_segflg is set.
+ */
+cpass()
+{
+       register c, id;
+
+       if(u.u_count == 0)
+               return(-1);
+       if((id = u.u_segflg) == 1)
+               c = *u.u_base;
+       else
+               if((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
+                       u.u_error = EFAULT;
+                       return(-1);
+               }
+       u.u_count--;
+       u.u_offset++;
+       u.u_base++;
+       return(c&0377);
+}
+
+/*
+ * Routine which sets a user error; placed in
+ * illegal entries in the bdevsw and cdevsw tables.
+ */
+nodev()
+{
+
+       u.u_error = ENODEV;
+}
+
+/*
+ * Null routine; placed in insignificant entries
+ * in the bdevsw and cdevsw tables.
+ */
+nulldev()
+{
+}
diff --git a/usr/src/slowsys/sys/sys1.c b/usr/src/slowsys/sys/sys1.c
new file mode 100644 (file)
index 0000000..5abb6ed
--- /dev/null
@@ -0,0 +1,515 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/buf.h"
+#include "../h/reg.h"
+#include "../h/inode.h"
+#include "../h/seg.h"
+#include "../h/acct.h"
+#include "../h/page.h"
+
+/*
+ * exec system call, with and without environments.
+ */
+struct execa {
+       char    *fname;
+       char    **argp;
+       char    **envp;
+};
+
+exec()
+{
+       ((struct execa *)u.u_ap)->envp = NULL;
+       exece();
+}
+
+exece()
+{
+       register nc;
+       register char *cp;
+       register struct buf *bp;
+       register struct execa *uap;
+       int na, ne, bno, ucp, ap, c;
+       struct inode *ip;
+
+       if ((ip = namei(uchar, 0)) == NULL)
+               return;
+       bno = 0;
+       bp = 0;
+       if(access(ip, IEXEC))
+               goto bad;
+       if((ip->i_mode & IFMT) != IFREG ||
+          (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
+               u.u_error = EACCES;
+               goto bad;
+       }
+       /*
+        * Collect arguments on "file" in swap space.
+        */
+       na = 0;
+       ne = 0;
+       nc = 0;
+       uap = (struct execa *)u.u_ap;
+       if ((bno = malloc(swapmap,(NCARGS+BSIZE-1)/BSIZE)) == 0)
+               panic("Out of swap");
+       if (uap->argp) for (;;) {
+               ap = NULL;
+               if (uap->argp) {
+                       ap = fuword((caddr_t)uap->argp);
+                       uap->argp++;
+               }
+               if (ap==NULL && uap->envp) {
+                       uap->argp = NULL;
+                       if ((ap = fuword((caddr_t)uap->envp)) == NULL)
+                               break;
+                       uap->envp++;
+                       ne++;
+               }
+               if (ap==NULL)
+                       break;
+               na++;
+               if(ap == -1)
+                       u.u_error = EFAULT;
+               do {
+                       if (nc >= NCARGS-1)
+                               u.u_error = E2BIG;
+                       if ((c = fubyte((caddr_t)ap++)) < 0)
+                               u.u_error = EFAULT;
+                       if (u.u_error)
+                               goto bad;
+                       if ((nc&BMASK) == 0) {
+                               if (bp)
+                                       bawrite(bp);
+                               bp = getblk(swapdev, swplo+bno+(nc>>BSHIFT));
+                               cp = bp->b_un.b_addr;
+                       }
+                       nc++;
+                       *cp++ = c;
+               } while (c>0);
+       }
+       if (bp)
+               bawrite(bp);
+       bp = 0;
+       nc = (nc + NBPW-1) & ~(NBPW-1);
+       if (getxfile(ip, nc) || u.u_error)
+               goto bad;
+
+       /*
+        * copy back arglist
+        */
+
+       ucp = USRSTACK - nc - NBPW;
+       ap = ucp - na*NBPW - 3*NBPW;
+       u.u_ar0[SP] = ap;
+       suword((caddr_t)ap, na-ne);
+       nc = 0;
+       for (;;) {
+               ap += NBPW;
+               if (na==ne) {
+                       suword((caddr_t)ap, 0);
+                       ap += NBPW;
+               }
+               if (--na < 0)
+                       break;
+               suword((caddr_t)ap, ucp);
+               do {
+                       if ((nc&BMASK) == 0) {
+                               if (bp)
+                                       brelse(bp);
+                               bp = bread(swapdev, swplo+bno+(nc>>BSHIFT));
+                               cp = bp->b_un.b_addr;
+                       }
+                       subyte((caddr_t)ucp++, (c = *cp++));
+                       nc++;
+               } while(c&0377);
+       }
+       suword((caddr_t)ap, 0);
+       suword((caddr_t)ucp, 0);
+       setregs();
+bad:
+       if (bp)
+               brelse(bp);
+       if(bno)
+               mfree(swapmap, (NCARGS+BSIZE-1)/BSIZE, bno);
+       iput(ip);
+}
+
+/*
+ * Read in and set up memory for executed file.
+ * Zero return is normal;
+ * non-zero means only the text is being replaced
+ */
+getxfile(ip, nargc)
+register struct inode *ip;
+{
+       register unsigned ds;
+       register sep;
+       register unsigned ts, ss;
+       register i, overlay;
+
+       /*
+        * read in first few bytes
+        * of file for segment
+        * sizes:
+        * ux_mag = 407/410/411/405
+        *  407 is plain executable
+        *  410 is RO text
+        *  411 is separated ID
+        *  405 is overlaid text
+        */
+
+       u.u_base = (caddr_t)&u.u_exdata;
+       u.u_count = sizeof(u.u_exdata);
+       u.u_offset = 0;
+       u.u_segflg = 1;
+       readi(ip);
+       u.u_segflg = 0;
+       if(u.u_error)
+               goto bad;
+       if (u.u_count!=0) {
+               u.u_error = ENOEXEC;
+               goto bad;
+       }
+       sep = 0;
+       overlay = 0;
+       if(u.u_exdata.ux_mag == 0407) {
+               u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
+               u.u_exdata.ux_tsize = 0;
+       } else if (u.u_exdata.ux_mag == 0411)
+               sep++;
+       else if (u.u_exdata.ux_mag == 0405)
+               overlay++;
+       else if (u.u_exdata.ux_mag != 0410) {
+               u.u_error = ENOEXEC;
+               goto bad;
+       }
+       if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
+               u.u_error = ETXTBSY;
+               goto bad;
+       }
+
+       /*
+        * find text and data sizes
+        * try them out for possible
+        * exceed of max sizes
+        */
+
+       ts = btoc(u.u_exdata.ux_tsize);
+       ds = btoc(u.u_exdata.ux_dsize + u.u_exdata.ux_bsize);
+       ss = SSIZE + btoc(nargc);
+       if (overlay) {
+               if (u.u_sep==0 && ctos(ts) != ctos(u.u_tsize) || nargc) {
+                       u.u_error = ENOMEM;
+                       goto bad;
+               }
+               ds = u.u_dsize;
+               ss = u.u_ssize;
+               sep = u.u_sep;
+               xfree();
+               xalloc(ip);
+               u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
+       } else {
+               if(estabur(ts, ds, ss, sep, RO))
+                       goto bad;
+       
+               /*
+                * allocate and clear core
+                * at this point, committed
+                * to the new image
+                */
+       
+               u.u_prof.pr_scale = 0;
+               xfree();
+               i = USIZE+ds+ss;
+               expand(i);
+               while(--i >= USIZE)
+                       clearseg(u.u_procp->p_addr+i);
+               xalloc(ip);
+       
+               /*
+                * read in data segment
+                */
+       
+               estabur((unsigned)0, ds, (unsigned)0, 0, RO);
+               u.u_base = 0;
+               u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize;
+               u.u_count = u.u_exdata.ux_dsize;
+               readi(ip);
+               /*
+                * set SUID/SGID protections, if no tracing
+                */
+               if ((u.u_procp->p_flag&STRC)==0) {
+                       if(ip->i_mode&ISUID)
+                               if(u.u_uid != 0) {
+                                       u.u_uid = ip->i_uid;
+                                       u.u_procp->p_uid = ip->i_uid;
+                               }
+                       if(ip->i_mode&ISGID)
+                               u.u_gid = ip->i_gid;
+               } else
+                       psignal(u.u_procp, SIGTRC);
+       }
+       u.u_tsize = ts;
+       u.u_dsize = ds;
+       u.u_ssize = ss;
+       u.u_sep = sep;
+       estabur(ts, ds, ss, sep, RO);
+bad:
+       return(overlay);
+}
+
+/*
+ * Clear registers on exec
+ */
+setregs()
+{
+       register int *rp;
+       register char *cp;
+       register i;
+
+       for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
+               if((*rp & 1) == 0)
+                       *rp = 0;
+/*
+       for(rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
+               *rp++ = 0;
+*/
+       u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
+       for(i=0; i<NOFILE; i++) {
+               if (u.u_pofile[i]&EXCLOSE) {
+                       closef(u.u_ofile[i]);
+                       u.u_ofile[i] = NULL;
+               }
+       }
+       /*
+        * Remember file name for accounting.
+        */
+       u.u_acflag &= ~AFORK;
+       bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ);
+}
+
+/*
+ * exit system call:
+ * pass back caller's arg
+ */
+rexit()
+{
+       register struct a {
+               int     rval;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       exit((uap->rval & 0377) << 8);
+}
+
+/*
+ * Release resources.
+ * Save u. area for parent to look at.
+ * Enter zombie state.
+ * Wake up parent and init processes,
+ * and dispose of children.
+ */
+exit(rv)
+{
+       register int i;
+       register struct proc *p, *q;
+       register struct file *f;
+
+       p = u.u_procp;
+       p->p_flag &= ~(STRC|SULOCK);
+       p->p_clktim = 0;
+       for(i=0; i<NSIG; i++)
+               u.u_signal[i] = 1;
+       for(i=0; i<NOFILE; i++) {
+               f = u.u_ofile[i];
+               u.u_ofile[i] = NULL;
+               closef(f);
+       }
+       plock(u.u_cdir);
+       iput(u.u_cdir);
+       if (u.u_rdir) {
+               plock(u.u_rdir);
+               iput(u.u_rdir);
+       }
+       xfree();
+       acct();
+       mfree(coremap, p->p_size, p->p_addr);
+       p->p_stat = SZOMB;
+       ((struct xproc *)p)->xp_xstat = rv;
+       ((struct xproc *)p)->xp_utime = u.u_cutime + u.u_utime;
+       ((struct xproc *)p)->xp_stime = u.u_cstime + u.u_stime;
+       for(q = &proc[0]; q < &proc[NPROC]; q++)
+               if(q->p_ppid == p->p_pid) {
+                       wakeup((caddr_t)&proc[1]);
+                       q->p_ppid = 1;
+                       if (q->p_stat==SSTOP)
+                               setrun(q);
+               }
+       for(q = &proc[0]; q < &proc[NPROC]; q++)
+               if(p->p_ppid == q->p_pid) {
+                       wakeup((caddr_t)q);
+                       swtch();
+                       /* no return */
+               }
+       swtch();
+}
+
+/*
+ * Wait system call.
+ * Search for a terminated (zombie) child,
+ * finally lay it to rest, and collect its status.
+ * Look also for stopped (traced) children,
+ * and pass back status from them.
+ */
+wait()
+{
+       register f;
+       register struct proc *p;
+
+       f = 0;
+
+loop:
+       for(p = &proc[0]; p < &proc[NPROC]; p++)
+       if(p->p_ppid == u.u_procp->p_pid) {
+               f++;
+               if(p->p_stat == SZOMB) {
+                       u.u_r.r_val1 = p->p_pid;
+                       u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat;
+                       u.u_cutime += ((struct xproc *)p)->xp_utime;
+                       u.u_cstime += ((struct xproc *)p)->xp_stime;
+                       p->p_stat = NULL;
+                       p->p_pid = 0;
+                       p->p_ppid = 0;
+                       p->p_sig = 0;
+                       p->p_pgrp = 0;
+                       p->p_flag = 0;
+                       p->p_wchan = 0;
+                       return;
+               }
+               if(p->p_stat == SSTOP) {
+                       if((p->p_flag&SWTED) == 0) {
+                               p->p_flag |= SWTED;
+                               u.u_r.r_val1 = p->p_pid;
+                               u.u_r.r_val2 = (fsig(p)<<8) | 0177;
+                               return;
+                       }
+                       continue;
+               }
+       }
+       if(f) {
+               sleep((caddr_t)u.u_procp, PWAIT);
+               goto loop;
+       }
+       u.u_error = ECHILD;
+}
+
+/*
+ * fork system call.
+ */
+fork()
+{
+       register struct proc *p1, *p2;
+       register a;
+
+       /*
+        * Make sure there's enough swap space for max
+        * core image, thus reducing chances of running out
+        */
+       if ((a = malloc(swapmap, ctod(MAXMEM))) == 0) {
+               u.u_error = ENOMEM;
+               goto out;
+       }
+       mfree(swapmap, ctod(MAXMEM), a);
+       a = 0;
+       p2 = NULL;
+       for(p1 = &proc[0]; p1 < &proc[NPROC]; p1++) {
+               if (p1->p_stat==NULL && p2==NULL)
+                       p2 = p1;
+               else {
+                       if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
+                               a++;
+               }
+       }
+       /*
+        * Disallow if
+        *  No processes at all;
+        *  not su and too many procs owned; or
+        *  not su and would take last slot.
+        */
+       if (p2==NULL || (u.u_uid!=0 && (p2==&proc[NPROC-1] || a>MAXUPRC))) {
+               u.u_error = EAGAIN;
+               goto out;
+       }
+       p1 = u.u_procp;
+       if(newproc()) {
+               u.u_r.r_val1 = p1->p_pid;
+               u.u_r.r_val2 = 1;  /* child */
+               u.u_start = time;
+               u.u_cstime = 0;
+               u.u_stime = 0;
+               u.u_cutime = 0;
+               u.u_utime = 0;
+               u.u_acflag = AFORK;
+               return;
+       }
+       u.u_r.r_val1 = p2->p_pid;
+
+out:
+       u.u_r.r_val2 = 0;
+}
+
+/*
+ * break system call.
+ *  -- bad planning: "break" is a dirty word in C.
+ */
+sbreak()
+{
+       struct a {
+               char    *nsiz;
+       };
+       register a, n, d;
+       int i;
+
+       /*
+        * set n to new data size
+        * set d to new-old
+        * set n to new total size
+        */
+
+       n = btoc((int)((struct a *)u.u_ap)->nsiz);
+       if(!u.u_sep)
+               n -= ctos(u.u_tsize) * stoc(1);
+       if(n < 0)
+               n = 0;
+       d = n - u.u_dsize;
+       n += USIZE+u.u_ssize;
+       if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO))
+               return;
+       u.u_dsize += d;
+       if(d > 0)
+               goto bigger;
+       a = u.u_procp->p_addr + n - u.u_ssize;
+       i = n;
+       n = u.u_ssize;
+       while(n--) {
+               copyseg(a-d, a);
+               a++;
+       }
+       expand(i);
+       return;
+
+bigger:
+       expand(n);
+       a = u.u_procp->p_addr + n;
+       n = u.u_ssize;
+       while(n--) {
+               a--;
+               copyseg(a-d, a);
+       }
+       while(d--)
+               clearseg(--a);
+}
diff --git a/usr/src/slowsys/sys/sys2.c b/usr/src/slowsys/sys/sys2.c
new file mode 100644 (file)
index 0000000..01e14c1
--- /dev/null
@@ -0,0 +1,317 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+
+/*
+ * read system call
+ */
+read()
+{
+       rdwr(FREAD);
+}
+
+/*
+ * write system call
+ */
+write()
+{
+       rdwr(FWRITE);
+}
+
+/*
+ * common code for read and write calls:
+ * check permissions, set base, count, and offset,
+ * and switch out to readi, writei, or pipe code.
+ */
+rdwr(mode)
+register mode;
+{
+       register struct file *fp;
+       register struct inode *ip;
+       register struct a {
+               int     fdes;
+               char    *cbuf;
+               unsigned count;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if(fp == NULL)
+               return;
+       if((fp->f_flag&mode) == 0) {
+               u.u_error = EBADF;
+               return;
+       }
+       u.u_base = (caddr_t)uap->cbuf;
+       u.u_count = uap->count;
+       u.u_segflg = 0;
+       if((fp->f_flag&FPIPE) != 0) {
+               if(mode == FREAD)
+                       readp(fp);
+               else
+                       writep(fp);
+       } else {
+               ip = fp->f_inode;
+               if (fp->f_flag&FMP)
+                       u.u_offset = 0;
+               else
+                       u.u_offset = fp->f_un.f_offset;
+               if((ip->i_mode&(IFCHR&IFBLK)) == 0)
+                       plock(ip);
+               if(mode == FREAD)
+                       readi(ip);
+               else
+                       writei(ip);
+               if((ip->i_mode&(IFCHR&IFBLK)) == 0)
+                       prele(ip);
+               if ((fp->f_flag&FMP) == 0)
+                       fp->f_un.f_offset += uap->count-u.u_count;
+       }
+       u.u_r.r_val1 = uap->count-u.u_count;
+}
+
+/*
+ * open system call
+ */
+open()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     rwmode;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return;
+       open1(ip, ++uap->rwmode, 0);
+}
+
+/*
+ * creat system call
+ */
+creat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     fmode;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 1);
+       if(ip == NULL) {
+               if(u.u_error)
+                       return;
+               ip = maknode(uap->fmode&07777&(~ISVTX));
+               if (ip==NULL)
+                       return;
+               open1(ip, FWRITE, 2);
+       } else
+               open1(ip, FWRITE, 1);
+}
+
+/*
+ * common code for open and creat.
+ * Check permissions, allocate an open file structure,
+ * and call the device open routine if any.
+ */
+open1(ip, mode, trf)
+register struct inode *ip;
+register mode;
+{
+       register struct file *fp;
+       int i;
+
+       if(trf != 2) {
+               if(mode&FREAD)
+                       access(ip, IREAD);
+               if(mode&FWRITE) {
+                       access(ip, IWRITE);
+                       if((ip->i_mode&IFMT) == IFDIR)
+                               u.u_error = EISDIR;
+               }
+       }
+       if(u.u_error)
+               goto out;
+       if(trf == 1)
+               itrunc(ip);
+       prele(ip);
+       if ((fp = falloc()) == NULL)
+               goto out;
+       fp->f_flag = mode&(FREAD|FWRITE);
+       fp->f_inode = ip;
+       i = u.u_r.r_val1;
+       openi(ip, mode&FWRITE);
+       if(u.u_error == 0)
+               return;
+       u.u_ofile[i] = NULL;
+       fp->f_count--;
+
+out:
+       iput(ip);
+}
+
+/*
+ * close system call
+ */
+close()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if(fp == NULL)
+               return;
+       u.u_ofile[uap->fdes] = NULL;
+       closef(fp);
+}
+
+/*
+ * seek system call
+ */
+seek()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+               off_t   off;
+               int     sbase;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if(fp == NULL)
+               return;
+       if(fp->f_flag&(FPIPE|FMP)) {
+               u.u_error = ESPIPE;
+               return;
+       }
+       if(uap->sbase == 1)
+               uap->off += fp->f_un.f_offset;
+       else if(uap->sbase == 2)
+               uap->off += fp->f_inode->i_size;
+       fp->f_un.f_offset = uap->off;
+       u.u_r.r_off = uap->off;
+}
+
+
+/*
+ * link system call
+ */
+link()
+{
+       register struct inode *ip, *xp;
+       register struct a {
+               char    *target;
+               char    *linkname;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return;
+       if((ip->i_mode&IFMT)==IFDIR && !suser())
+               goto out;
+       /*
+        * Unlock to avoid possibly hanging the namei.
+        * Sadly, this means races. (Suppose someone
+        * deletes the file in the meantime?)
+        * Nor can it be locked again later
+        * because then there will be deadly
+        * embraces.
+        */
+       prele(ip);
+       u.u_dirp = (caddr_t)uap->linkname;
+       xp = namei(uchar, 1);
+       if(xp != NULL) {
+               u.u_error = EEXIST;
+               iput(xp);
+               goto out;
+       }
+       if (u.u_error)
+               goto out;
+       if(u.u_pdir->i_dev != ip->i_dev) {
+               iput(u.u_pdir);
+               u.u_error = EXDEV;
+               goto out;
+       }
+       wdir(ip);
+       if (u.u_error==0) {
+               ip->i_nlink++;
+               ip->i_flag |= ICHG;
+       }
+
+out:
+       iput(ip);
+}
+
+/*
+ * mknod system call
+ */
+mknod()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     fmode;
+               int     dev;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if(suser()) {
+               ip = namei(uchar, 1);
+               if(ip != NULL) {
+                       u.u_error = EEXIST;
+                       goto out;
+               }
+       }
+       if(u.u_error)
+               return;
+       ip = maknode(uap->fmode);
+       if (ip == NULL)
+               return;
+       ip->i_un.i_rdev = (dev_t)uap->dev;
+
+out:
+       iput(ip);
+}
+
+/*
+ * access system call
+ */
+saccess()
+{
+       register svuid, svgid;
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     fmode;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       svuid = u.u_uid;
+       svgid = u.u_gid;
+       u.u_uid = u.u_ruid;
+       u.u_gid = u.u_rgid;
+       ip = namei(uchar, 0);
+       if (ip != NULL) {
+               if (uap->fmode&(IREAD>>6))
+                       access(ip, IREAD);
+               if (uap->fmode&(IWRITE>>6))
+                       access(ip, IWRITE);
+               if (uap->fmode&(IEXEC>>6))
+                       access(ip, IEXEC);
+               iput(ip);
+       }
+       u.u_uid = svuid;
+       u.u_gid = svgid;
+}
diff --git a/usr/src/slowsys/sys/sys3.c b/usr/src/slowsys/sys/sys3.c
new file mode 100644 (file)
index 0000000..1523d25
--- /dev/null
@@ -0,0 +1,255 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mount.h"
+#include "../h/ino.h"
+#include "../h/reg.h"
+#include "../h/buf.h"
+#include "../h/filsys.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/conf.h"
+#include "../h/stat.h"
+
+/*
+ * the fstat system call.
+ */
+fstat()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       fp = getf(uap->fdes);
+       if(fp == NULL)
+               return;
+       stat1(fp->f_inode, uap->sb, fp->f_flag&FPIPE? fp->f_un.f_offset: 0);
+}
+
+/*
+ * the stat system call.
+ */
+stat()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               struct stat *sb;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return;
+       stat1(ip, uap->sb, (off_t)0);
+       iput(ip);
+}
+
+/*
+ * The basic routine for fstat and stat:
+ * get the inode and pass appropriate parts back.
+ */
+stat1(ip, ub, pipeadj)
+register struct inode *ip;
+struct stat *ub;
+off_t pipeadj;
+{
+       register struct dinode *dp;
+       register struct buf *bp;
+       struct stat ds;
+
+       iupdat(ip, &time, &time);
+       /*
+        * first copy from inode table
+        */
+       ds.st_dev = ip->i_dev;
+       ds.st_ino = ip->i_number;
+       ds.st_mode = ip->i_mode;
+       ds.st_nlink = ip->i_nlink;
+       ds.st_uid = ip->i_uid;
+       ds.st_gid = ip->i_gid;
+       ds.st_rdev = (dev_t)ip->i_un.i_rdev;
+       ds.st_size = ip->i_size - pipeadj;
+       /*
+        * next the dates in the disk
+        */
+       bp = bread(ip->i_dev, itod(ip->i_number));
+       dp = bp->b_un.b_dino;
+       dp += itoo(ip->i_number);
+       ds.st_atime = dp->di_atime;
+       ds.st_mtime = dp->di_mtime;
+       ds.st_ctime = dp->di_ctime;
+       brelse(bp);
+       if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
+               u.u_error = EFAULT;
+}
+
+/*
+ * the dup system call.
+ */
+dup()
+{
+       register struct file *fp;
+       register struct a {
+               int     fdes;
+               int     fdes2;
+       } *uap;
+       register i, m;
+
+       uap = (struct a *)u.u_ap;
+       m = uap->fdes & ~077;
+       uap->fdes &= 077;
+       fp = getf(uap->fdes);
+       if(fp == NULL)
+               return;
+       if ((m&0100) == 0) {
+               if ((i = ufalloc()) < 0)
+                       return;
+       } else {
+               i = uap->fdes2;
+               if (i<0 || i>=NOFILE) {
+                       u.u_error = EBADF;
+                       return;
+               }
+               u.u_r.r_val1 = i;
+       }
+       if (i!=uap->fdes) {
+               if (u.u_ofile[i]!=NULL)
+                       closef(u.u_ofile[i]);
+               u.u_ofile[i] = fp;
+               fp->f_count++;
+       }
+}
+
+/*
+ * the mount system call.
+ */
+smount()
+{
+       dev_t dev;
+       register struct inode *ip;
+       register struct mount *mp;
+       struct mount *smp;
+       register struct filsys *fp;
+       struct buf *bp;
+       register struct a {
+               char    *fspec;
+               char    *freg;
+               int     ronly;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       dev = getmdev();
+       if(u.u_error)
+               return;
+       u.u_dirp = (caddr_t)uap->freg;
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return;
+       if(ip->i_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0)
+               goto out;
+       smp = NULL;
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
+               if(mp->m_bufp != NULL) {
+                       if(dev == mp->m_dev)
+                               goto out;
+               } else
+               if(smp == NULL)
+                       smp = mp;
+       }
+       mp = smp;
+       if(mp == NULL)
+               goto out;
+       (*bdevsw[major(dev)].d_open)(dev, !uap->ronly);
+       if(u.u_error)
+               goto out;
+       bp = bread(dev, SUPERB);
+       if(u.u_error) {
+               brelse(bp);
+               goto out1;
+       }
+       mp->m_inodp = ip;
+       mp->m_dev = dev;
+       mp->m_bufp = geteblk();
+       bcopy((caddr_t)bp->b_un.b_addr, mp->m_bufp->b_un.b_addr, BSIZE);
+       fp = mp->m_bufp->b_un.b_filsys;
+       fp->s_ilock = 0;
+       fp->s_flock = 0;
+       fp->s_ronly = uap->ronly & 1;
+       brelse(bp);
+       ip->i_flag |= IMOUNT;
+       prele(ip);
+       return;
+
+out:
+       u.u_error = EBUSY;
+out1:
+       iput(ip);
+}
+
+/*
+ * the umount system call.
+ */
+sumount()
+{
+       dev_t dev;
+       register struct inode *ip;
+       register struct mount *mp;
+       struct buf *bp;
+       register struct a {
+               char    *fspec;
+       };
+
+       dev = getmdev();
+       if(u.u_error)
+               return;
+       xumount(dev);   /* remove unused sticky files from text table */
+       update();
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+               if(mp->m_bufp != NULL && dev == mp->m_dev)
+                       goto found;
+       u.u_error = EINVAL;
+       return;
+
+found:
+       for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
+               if(ip->i_number != 0 && dev == ip->i_dev) {
+                       u.u_error = EBUSY;
+                       return;
+               }
+       (*bdevsw[major(dev)].d_close)(dev, 0);
+       ip = mp->m_inodp;
+       ip->i_flag &= ~IMOUNT;
+       plock(ip);
+       iput(ip);
+       bp = mp->m_bufp;
+       mp->m_bufp = NULL;
+       brelse(bp);
+}
+
+/*
+ * Common code for mount and umount.
+ * Check that the user's argument is a reasonable
+ * thing on which to mount, and return the device number if so.
+ */
+dev_t
+getmdev()
+{
+       dev_t dev;
+       register struct inode *ip;
+
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return(NODEV);
+       if((ip->i_mode&IFMT) != IFBLK)
+               u.u_error = ENOTBLK;
+       dev = (dev_t)ip->i_un.i_rdev;
+       if(major(dev) >= nblkdev)
+               u.u_error = ENXIO;
+       iput(ip);
+       return(dev);
+}
diff --git a/usr/src/slowsys/sys/sys4.c b/usr/src/slowsys/sys/sys4.c
new file mode 100644 (file)
index 0000000..c454a9e
--- /dev/null
@@ -0,0 +1,459 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/reg.h"
+#include "../h/inode.h"
+#include "../h/proc.h"
+#include "../h/clock.h"
+#include "../h/mtpr.h"
+#include "../h/timeb.h"
+
+/*
+ * Everything in this file is a routine implementing a system call.
+ */
+
+/*
+ * return the current time (old-style entry)
+ */
+gtime()
+{
+       u.u_r.r_time = time;
+}
+
+/*
+ * New time entry-- return TOD with milliseconds, timezone,
+ * DST flag
+ */
+ftime()
+{
+       register struct a {
+               struct  timeb   *tp;
+       } *uap;
+       struct timeb t;
+       register unsigned ms;
+
+       uap = (struct a *)u.u_ap;
+       spl7();
+       t.time = time;
+       ms = lbolt;
+       spl0();
+       if (ms > HZ) {
+               ms -= HZ;
+               t.time++;
+       }
+       t.millitm = (1000*ms)/HZ;
+       t.timezone = TIMEZONE;
+       t.dstflag = DSTFLAG;
+       if (copyout((caddr_t)&t, (caddr_t)uap->tp, sizeof(t)) < 0)
+               u.u_error = EFAULT;
+}
+
+/*
+ * Set the time
+ */
+stime()
+{
+       register unsigned int i , j ;
+       register struct a {
+               time_t  time;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if(suser()) {
+               time = uap->time;
+               /* In addition to setting software time (GMT seconds
+               *  since YRREF), also set VAX TODR reg (10 ms. clicks
+               *  into current year YRCURR
+               */
+               for (i = time , j = YRREF ; j < YRCURR ; j++)
+                       i -= (SECYR + (j%4?0:SECDAY)) ;
+               mtpr(TODR,i*100) ; /* 10 ms. clicks */
+       }
+}
+
+setuid()
+{
+       register uid;
+       register struct a {
+               int     uid;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       uid = uap->uid;
+       if(u.u_ruid == uid || suser()) {
+               u.u_uid = uid;
+               u.u_procp->p_uid = uid;
+               u.u_ruid = uid;
+       }
+}
+
+getuid()
+{
+
+       u.u_r.r_val1 = u.u_ruid;
+       u.u_r.r_val2 = u.u_uid;
+}
+
+setgid()
+{
+       register gid;
+       register struct a {
+               int     gid;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       gid = uap->gid;
+       if(u.u_rgid == gid || suser()) {
+               u.u_gid = gid;
+               u.u_rgid = gid;
+       }
+}
+
+getgid()
+{
+
+       u.u_r.r_val1 = u.u_rgid;
+       u.u_r.r_val2 = u.u_gid;
+}
+
+getpid()
+{
+       u.u_r.r_val1 = u.u_procp->p_pid;
+       u.u_r.r_val2 = u.u_procp->p_ppid;
+}
+
+sync()
+{
+
+       update();
+}
+
+nice()
+{
+       register n;
+       register struct a {
+               int     niceness;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       n = uap->niceness;
+       if(n < 0 && !suser())
+               n = 0;
+       n += u.u_procp->p_nice;
+       if(n >= 2*NZERO)
+               n = 2*NZERO -1;
+       if(n < 0)
+               n = 0;
+       u.u_procp->p_nice = n;
+}
+
+/*
+ * Unlink system call.
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+unlink()
+{
+       register struct inode *ip, *pp;
+       struct a {
+               char    *fname;
+       };
+
+       pp = namei(uchar, 2);
+       if(pp == NULL)
+               return;
+       /*
+        * Check for unlink(".")
+        * to avoid hanging on the iget
+        */
+       if (pp->i_number == u.u_dent.d_ino) {
+               ip = pp;
+               ip->i_count++;
+       } else
+               ip = iget(pp->i_dev, u.u_dent.d_ino);
+       if(ip == NULL)
+               goto out1;
+       if((ip->i_mode&IFMT)==IFDIR && !suser())
+               goto out;
+       /*
+        * Don't unlink a mounted file.
+        */
+       if (ip->i_dev != pp->i_dev) {
+               u.u_error = EBUSY;
+               goto out;
+       }
+       if (ip->i_flag&ITEXT)
+               xrele(ip);      /* try once to free text */
+       if (ip->i_flag&ITEXT && ip->i_nlink==1) {
+               u.u_error = ETXTBSY;
+               goto out;
+       }
+       u.u_offset -= sizeof(struct direct);
+       u.u_base = (caddr_t)&u.u_dent;
+       u.u_count = sizeof(struct direct);
+       u.u_dent.d_ino = 0;
+       writei(pp);
+       ip->i_nlink--;
+       ip->i_flag |= ICHG;
+
+out:
+       iput(ip);
+out1:
+       iput(pp);
+}
+chdir()
+{
+       chdirec(&u.u_cdir);
+}
+
+chroot()
+{
+       chdirec(&u.u_rdir);
+}
+
+chdirec(ipp)
+register struct inode **ipp;
+{
+       register struct inode *ip;
+       struct a {
+               char    *fname;
+       };
+
+       ip = namei(uchar, 0);
+       if(ip == NULL)
+               return;
+       if((ip->i_mode&IFMT) != IFDIR) {
+               u.u_error = ENOTDIR;
+               goto bad;
+       }
+       if(access(ip, IEXEC))
+               goto bad;
+       prele(ip);
+       if (*ipp) {
+               plock(*ipp);
+               iput(*ipp);
+       }
+       *ipp = ip;
+       return;
+
+bad:
+       iput(ip);
+}
+
+chmod()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     fmode;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if ((ip = owner()) == NULL)
+               return;
+       ip->i_mode &= ~07777;
+       if (u.u_uid)
+               uap->fmode &= ~ISVTX;
+       ip->i_mode |= uap->fmode&07777;
+       ip->i_flag |= ICHG;
+       if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
+               xrele(ip);
+       iput(ip);
+}
+
+chown()
+{
+       register struct inode *ip;
+       register struct a {
+               char    *fname;
+               int     uid;
+               int     gid;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (!suser() || (ip = owner()) == NULL)
+               return;
+       ip->i_uid = uap->uid;
+       ip->i_gid = uap->gid;
+       ip->i_flag |= ICHG;
+       iput(ip);
+}
+
+ssig()
+{
+       register a;
+       struct a {
+               int     signo;
+               int     fun;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       a = uap->signo;
+       if(a<=0 || a>=NSIG || a==SIGKIL) {
+               u.u_error = EINVAL;
+               return;
+       }
+       u.u_r.r_val1 = u.u_signal[a];
+       u.u_signal[a] = uap->fun;
+       u.u_procp->p_sig &= ~(1<<(a-1));
+}
+
+kill()
+{
+       register struct proc *p, *q;
+       register a;
+       register struct a {
+               int     pid;
+               int     signo;
+       } *uap;
+       int f, priv;
+
+       uap = (struct a *)u.u_ap;
+       f = 0;
+       a = uap->pid;
+       priv = 0;
+       if (a==-1 && u.u_uid==0) {
+               priv++;
+               a = 0;
+       }
+       q = u.u_procp;
+       for(p = &proc[0]; p < &proc[NPROC]; p++) {
+               if(p->p_stat == NULL)
+                       continue;
+               if(a != 0 && p->p_pid != a)
+                       continue;
+               if(a==0 && ((p->p_pgrp!=q->p_pgrp&&priv==0) || p<=&proc[1]))
+                       continue;
+               if(u.u_uid != 0 && u.u_uid != p->p_uid)
+                       continue;
+               f++;
+               psignal(p, uap->signo);
+       }
+       if(f == 0)
+               u.u_error = ESRCH;
+}
+
+times()
+{
+       register struct a {
+               time_t  (*times)[4];
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (copyout((caddr_t)&u.u_utime, (caddr_t)uap->times, sizeof(*uap->times)) < 0)
+               u.u_error = EFAULT;
+}
+
+profil()
+{
+       register struct a {
+               short   *bufbase;
+               unsigned bufsize;
+               unsigned pcoffset;
+               unsigned pcscale;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       u.u_prof.pr_base = uap->bufbase;
+       u.u_prof.pr_size = uap->bufsize;
+       u.u_prof.pr_off = uap->pcoffset;
+       u.u_prof.pr_scale = uap->pcscale;
+}
+
+/*
+ * alarm clock signal
+ */
+alarm()
+{
+       register struct proc *p;
+       register c;
+       register struct a {
+               int     deltat;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       p = u.u_procp;
+       c = p->p_clktim;
+       p->p_clktim = uap->deltat;
+       u.u_r.r_val1 = c;
+}
+
+/*
+ * indefinite wait.
+ * no one should wakeup(&u)
+ */
+pause()
+{
+
+       for(;;)
+               sleep((caddr_t)&u, PSLEP);
+}
+
+/*
+ * mode mask for creation of files
+ */
+umask()
+{
+       register struct a {
+               int     mask;
+       } *uap;
+       register t;
+
+       uap = (struct a *)u.u_ap;
+       t = u.u_cmask;
+       u.u_cmask = uap->mask & 0777;
+       u.u_r.r_val1 = t;
+}
+
+/*
+ * Set IUPD and IACC times on file.
+ * Can't set ICHG.
+ */
+utime()
+{
+       register struct a {
+               char    *fname;
+               time_t  *tptr;
+       } *uap;
+       register struct inode *ip;
+       time_t tv[2];
+
+       uap = (struct a *)u.u_ap;
+       if ((ip = owner()) == NULL)
+               return;
+       if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
+               u.u_error = EFAULT;
+               return;
+       }
+       ip->i_flag |= IACC|IUPD|ICHG;
+       iupdat(ip, &tv[0], &tv[1]);
+       iput(ip);
+}
+
+/*
+ * Get microseconds since system boot
+ */
+microtime()
+{
+       register struct a {
+               int     (*times)[2];
+       } *uap;
+
+       register int    clkcnt,clkstat,pri;
+       int     total[2];
+
+       uap = (struct a *)u.u_ap;
+       pri = spl7();
+       total[0] = time64[0];
+       total[1] = time64[1];
+       clkcnt = mfpr(ICR);
+       clkstat = mfpr(ICCS);
+       splx(pri);
+       clkcnt += CLKTICK;      /* microseconds since last tick */
+       if (clkstat & ICCS_ERR)
+               clkcnt += CLKTICK;      /* account for overflow */
+       add64(clkcnt,&total[0],&total[1]);
+       if (copyout((caddr_t)total,(caddr_t)uap->times,8))
+               u.u_error = EFAULT;
+}
diff --git a/usr/src/slowsys/sys/sysent.c b/usr/src/slowsys/sys/sysent.c
new file mode 100644 (file)
index 0000000..b62ca3f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * This table is the switch used to transfer
+ * to the appropriate routine for processing a system call.
+ * Each row contains the number of arguments expected
+ * and a pointer to the routine.
+ */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+
+int    alarm();
+int    chdir();
+int    chmod();
+int    chown();
+int    chroot();
+int    close();
+int    creat();
+int    dup();
+int    exec();
+int    exece();
+int    fork();
+int    fstat();
+int    getgid();
+int    getpid();
+int    getuid();
+int    gtime();
+int    gtty();
+int    ioctl();
+int    kill();
+int    link();
+int    mknod();
+int    mpxchan();
+int    nice();
+int    ftime();
+int    nosys();
+int    nullsys();
+int    open();
+int    pause();
+int    pipe();
+int    profil();
+int    ptrace();
+int    read();
+int    rexit();
+int    saccess();
+int    sbreak();
+int    seek();
+int    setgid();
+int    setuid();
+int    smount();
+int    ssig();
+int    stat();
+int    stime();
+int    stty();
+int    sumount();
+int    sync();
+int    sysacct();
+int    syslock();
+int    sysphys();
+int    times();
+int    umask();
+int    unlink();
+int    utime();
+int    wait();
+int    write();
+
+struct sysent sysent[64] =
+{
+       0, 0, nosys,                    /* 0 = indir */
+       1, 0, rexit,                    /*  1 = exit */
+       0, 0, fork,                     /*  2 = fork */
+       3, 0, read,                     /*  3 = read */
+       3, 0, write,                    /*  4 = write */
+       2, 0, open,                     /*  5 = open */
+       1, 0, close,                    /*  6 = close */
+       0, 0, wait,                     /*  7 = wait */
+       2, 0, creat,                    /*  8 = creat */
+       2, 0, link,                     /*  9 = link */
+       1, 0, unlink,                   /* 10 = unlink */
+       2, 0, exec,                     /* 11 = exec */
+       1, 0, chdir,                    /* 12 = chdir */
+       0, 0, gtime,                    /* 13 = time */
+       3, 0, mknod,                    /* 14 = mknod */
+       2, 0, chmod,                    /* 15 = chmod */
+       3, 0, chown,                    /* 16 = chown; now 3 args */
+       1, 0, sbreak,                   /* 17 = break */
+       2, 0, stat,                     /* 18 = stat */
+       3, 0, seek,                     /* 19 = seek */
+       0, 0, getpid,                   /* 20 = getpid */
+       3, 0, smount,                   /* 21 = mount */
+       1, 0, sumount,                  /* 22 = umount */
+       1, 0, setuid,                   /* 23 = setuid */
+       0, 0, getuid,                   /* 24 = getuid */
+       1, 0, stime,                    /* 25 = stime */
+       4, 0, ptrace,                   /* 26 = ptrace */
+       1, 0, alarm,                    /* 27 = alarm */
+       2, 0, fstat,                    /* 28 = fstat */
+       0, 0, pause,                    /* 29 = pause */
+       2, 0, utime,                    /* 30 = utime */
+       2, 0, stty,                     /* 31 = stty */
+       2, 0, gtty,                     /* 32 = gtty */
+       2, 0, saccess,                  /* 33 = access */
+       1, 0, nice,                     /* 34 = nice */
+       1, 0, ftime,                    /* 35 = ftime; formally sleep;  */
+       0, 0, sync,                     /* 36 = sync */
+       2, 0, kill,                     /* 37 = kill */
+       0, 0, nullsys,                  /* 38 = switch; inoperative */
+       0, 0, nullsys,                  /* 39 = setpgrp (not in yet) */
+       0, 0, nosys,                    /* 40 = tell - obsolete */
+       2, 0, dup,                              /* 41 = dup */
+       0, 0, pipe,                     /* 42 = pipe */
+       1, 0, times,                    /* 43 = times */
+       4, 0, profil,                   /* 44 = prof */
+       0, 0, nosys,                    /* 45 = tiu */
+       1, 0, setgid,                   /* 46 = setgid */
+       0, 0, getgid,                   /* 47 = getgid */
+       2, 0, ssig,                     /* 48 = sig */
+       0, 0, nosys,                    /* 49 = reserved for USG */
+       0, 0, nosys,                    /* 50 = reserved for USG */
+       1, 0, sysacct,                  /* 51 = turn acct off/on */
+       3, 0, sysphys,                  /* 52 = set user physical addresses */
+       1, 0, syslock,                  /* 53 = lock user in core */
+       3, 0, ioctl,                    /* 54 = ioctl */
+       0, 0, nosys,                    /* 55 = reboot */
+       4, 0, mpxchan,                  /* 56 = creat mpx comm channel */
+       0, 0, nosys,                    /* 57 = reserved for USG */
+       0, 0, nosys,                    /* 58 = reserved for USG */
+       3, 0, exece,                    /* 59 = exece */
+       1, 0, umask,                    /* 60 = umask */
+       1, 0, chroot,                   /* 61 = chroot */
+       1, 0, nosys,            /* 62 = unused */
+       0, 0, nosys                     /* 63 = used internally */
+};
diff --git a/usr/src/slowsys/sys/tdump.c b/usr/src/slowsys/sys/tdump.c
new file mode 100644 (file)
index 0000000..77f39fa
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Dump core to magtape
+ * Assumes memory mapping has been disabled
+ * and IPL has be set high ( > 0x15 )
+ */
+
+
+#define PHYSPAGES 1024
+#define UBA 0x20006000
+#define mba0 0x20010000
+#define mba1 0x20012000
+
+struct mba_regs {
+       int mba_csr,
+           mba_cr,
+           mba_sr,
+           mba_var,
+           mba_bcr;
+};
+
+struct device
+{
+       int     htcs1;
+       int     htds;
+       int     hter;
+       int     htmr;
+       int     htas;
+       int     htfc;
+       int     htdt;
+       int     htck;
+       int     htsn;
+       int     httc;
+};
+
+#define        HTADDR  ((struct device *)(mba1 + 0x400))
+#define HTMAP ((int *) (mba1 + 0x800))
+
+#define        GO      01
+#define        WCOM    060
+#define        RCOM    070
+#define        NOP     0
+#define        WEOF    026
+#define        SFORW   030
+#define        SREV    032
+#define        ERASE   024
+#define        REW     06
+#define        DCLR    010
+#define P800   01300           /* 800 + pdp11 mode */
+#define        P1600   02300           /* 1600 + pdp11 mode */
+#define        IENABLE 0100
+#define        RDY     0200
+#define        TM      04
+#define        DRY     0200
+#define EOT    02000
+#define CS     02000
+#define COR    0100000
+#define PES    040
+#define WRL    04000
+#define MOL    010000
+#define ERR    040000
+#define FCE    01000
+#define        TRE     040000
+#define HARD   064023  /* UNS|OPI|NEF|FMT|RMR|ILR|ILF */
+
+#define        SIO     1
+#define        SSFOR   2
+#define        SSREV   3
+#define SRETRY 4
+#define SCOM   5
+#define SOK    6
+
+dump()
+{
+
+       HTADDR->httc = P800;    /* set 800 bpi mode */
+
+       twall((char *)0, PHYSPAGES);    /* write out memory */
+
+       teof();
+       teof();
+       rewind();
+}
+
+twall(start, num)
+       char *start;
+       int num;
+{
+       HTADDR->htcs1 = DCLR | GO;
+       while (num--) {
+               twrite(start);
+               start += 512;
+               }
+}
+
+twrite(buf)
+char *buf;
+{
+
+       twait();
+       HTADDR->htfc = -512;
+       *HTMAP = (((int)buf)>>9) | 0x80000000;  /* map entry */
+       ((struct mba_regs *)mba1)->mba_sr = -1;
+       ((struct mba_regs *)mba1)->mba_bcr = -512;
+       ((struct mba_regs *)mba1)->mba_var = 0;
+       HTADDR->htcs1 = WCOM | GO;
+       return;
+}
+
+twait()
+{
+       register s;
+
+       do
+               s = HTADDR->htds;
+       while ((s & RDY) == 0);
+}
+
+rewind()
+{
+       twait();
+       HTADDR->htcs1 = REW | GO;
+}
+
+teof()
+{
+       twait();
+       HTADDR->htcs1 = WEOF | GO;
+}
diff --git a/usr/src/slowsys/sys/text.c b/usr/src/slowsys/sys/text.c
new file mode 100644 (file)
index 0000000..0e71464
--- /dev/null
@@ -0,0 +1,266 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/uba.h"
+#include "../h/map.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/text.h"
+#include "../h/inode.h"
+#include "../h/buf.h"
+#include "../h/seg.h"
+#include "../h/page.h"
+
+/*
+ * Swap out process p.
+ * The ff flag causes its core to be freed--
+ * it may be off when called to create an image for a
+ * child process in newproc.
+ * Os is the old size of the data area of the process,
+ * and is supplied during core expansion swaps.
+ *
+ * panic: out of swap space
+ */
+xswap(p, ff, os)
+register struct proc *p;
+{
+       register a;
+
+       if(os == 0)
+               os = p->p_size;
+       a = malloc(swapmap, ctod(p->p_size));
+       if(a == NULL)
+               panic("out of swap space");
+       p->p_flag |= SLOCK;
+       xccdec(p->p_textp);
+       swap(a, p->p_addr, os, B_WRITE);
+       if(ff)
+               mfree(coremap, os, p->p_addr);
+       p->p_addr = a;
+       p->p_flag &= ~(SLOAD|SLOCK);
+       p->p_time = 0;
+       if(runout) {
+               runout = 0;
+               wakeup((caddr_t)&runout);
+       }
+}
+
+/*
+ * relinquish use of the shared text segment
+ * of a process.
+ */
+xfree()
+{
+       register struct text *xp;
+       register struct inode *ip;
+
+       if((xp=u.u_procp->p_textp) == NULL)
+               return;
+       xlock(xp);
+       xp->x_flag &= ~XLOCK;
+       u.u_procp->p_textp = NULL;
+       ip = xp->x_iptr;
+       if(--xp->x_count==0 && (ip->i_mode&ISVTX)==0) {
+               xp->x_iptr = NULL;
+               mfree(swapmap, ctod(xp->x_size), xp->x_daddr);
+               mfree(coremap, xp->x_size, xp->x_caddr);
+               ip->i_flag &= ~ITEXT;
+               if (ip->i_flag&ILOCK)
+                       ip->i_count--;
+               else
+                       iput(ip);
+       } else
+               xccdec(xp);
+}
+
+/*
+ * Attach to a shared text segment.
+ * If there is no shared text, just return.
+ * If there is, hook up to it:
+ * if it is not currently being used, it has to be read
+ * in from the inode (ip); the written bit is set to force it
+ * to be written out as appropriate.
+ * If it is being used, but is not currently in core,
+ * a swap has to be done to get it back.
+ */
+xalloc(ip)
+register struct inode *ip;
+{
+       register struct text *xp;
+       register unsigned ts;
+       register struct text *xp1;
+
+       if(u.u_exdata.ux_tsize == 0)
+               return;
+       xp1 = NULL;
+       for (xp = &text[0]; xp < &text[NTEXT]; xp++) {
+               if(xp->x_iptr == NULL) {
+                       if(xp1 == NULL)
+                               xp1 = xp;
+                       continue;
+               }
+               if(xp->x_iptr == ip) {
+                       xlock(xp);
+                       xp->x_count++;
+                       u.u_procp->p_textp = xp;
+                       if (xp->x_ccount == 0)
+                               xexpand(xp);
+                       else
+                               xp->x_ccount++;
+                       xunlock(xp);
+                       return;
+               }
+       }
+       if((xp=xp1) == NULL) {
+               printf("out of text");
+               psignal(u.u_procp, SIGKIL);
+               return;
+       }
+       xp->x_flag = XLOAD|XLOCK;
+       xp->x_count = 1;
+       xp->x_ccount = 0;
+       xp->x_iptr = ip;
+       ip->i_flag |= ITEXT;
+       ip->i_count++;
+       ts = btoc(u.u_exdata.ux_tsize);
+       xp->x_size = ts;
+       if((xp->x_daddr = malloc(swapmap, ctod(ts))) == NULL)
+               panic("out of swap space");
+       u.u_procp->p_textp = xp;
+       xexpand(xp);
+       estabur(ts, (unsigned)0, (unsigned)0, 0, RW);
+       u.u_count = u.u_exdata.ux_tsize;
+       u.u_offset = sizeof(u.u_exdata);
+       u.u_base = 0;
+       u.u_segflg = 2;
+       u.u_procp->p_flag |= SLOCK;
+       readi(ip);
+       u.u_procp->p_flag &= ~SLOCK;
+       u.u_segflg = 0;
+       xp->x_flag = XWRIT;
+}
+
+/*
+ * Assure core for text segment
+ * Text must be locked to keep someone else from
+ * freeing it in the meantime.
+ * x_ccount must be 0.
+ */
+xexpand(xp)
+register struct text *xp;
+{
+       if ((xp->x_caddr = malloc(coremap, xp->x_size)) != NULL) {
+               if ((xp->x_flag&XLOAD)==0)
+                       swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_READ);
+               xp->x_ccount++;
+               xunlock(xp);
+               return;
+       }
+       if (save(u.u_ssav)) {
+               sureg();
+               return;
+       }
+       xswap(u.u_procp, 1, 0);
+       xunlock(xp);
+       u.u_procp->p_flag |= SSWAP;
+       qswtch();
+       /* no return */
+}
+
+/*
+ * Lock and unlock a text segment from swapping
+ */
+xlock(xp)
+register struct text *xp;
+{
+
+       while(xp->x_flag&XLOCK) {
+               xp->x_flag |= XWANT;
+               sleep((caddr_t)xp, PSWP);
+       }
+       xp->x_flag |= XLOCK;
+}
+
+xunlock(xp)
+register struct text *xp;
+{
+
+       if (xp->x_flag&XWANT)
+               wakeup((caddr_t)xp);
+       xp->x_flag &= ~(XLOCK|XWANT);
+}
+
+/*
+ * Decrement the in-core usage count of a shared text segment.
+ * When it drops to zero, free the core space.
+ */
+xccdec(xp)
+register struct text *xp;
+{
+
+       if (xp==NULL || xp->x_ccount==0)
+               return;
+       xlock(xp);
+       if (--xp->x_ccount==0) {
+               if (xp->x_flag&XWRIT) {
+                       xp->x_flag &= ~XWRIT;
+                       swap(xp->x_daddr,xp->x_caddr,xp->x_size,B_WRITE);
+               }
+               mfree(coremap, xp->x_size, xp->x_caddr);
+       }
+       xunlock(xp);
+}
+
+/*
+ * free the swap image of all unused saved-text text segments
+ * which are from device dev (used by umount system call).
+ */
+xumount(dev)
+register dev;
+{
+       register struct text *xp;
+
+       for (xp = &text[0]; xp < &text[NTEXT]; xp++) 
+               if (xp->x_iptr!=NULL && dev==xp->x_iptr->i_dev)
+                       xuntext(xp);
+}
+
+/*
+ * remove a shared text segment from the text table, if possible.
+ */
+xrele(ip)
+register struct inode *ip;
+{
+       register struct text *xp;
+
+       if (ip->i_flag&ITEXT==0)
+               return;
+       for (xp = &text[0]; xp < &text[NTEXT]; xp++)
+               if (ip==xp->x_iptr)
+                       xuntext(xp);
+}
+
+/*
+ * remove text image from the text table.
+ * the use count must be zero.
+ */
+xuntext(xp)
+register struct text *xp;
+{
+       register struct inode *ip;
+
+       xlock(xp);
+       if (xp->x_count) {
+               xunlock(xp);
+               return;
+       }
+       ip = xp->x_iptr;
+       xp->x_flag &= ~XLOCK;
+       xp->x_iptr = NULL;
+       mfree(swapmap, ctod(xp->x_size), xp->x_daddr);
+       ip->i_flag &= ~ITEXT;
+       if (ip->i_flag&ILOCK)
+               ip->i_count--;
+       else
+               iput(ip);
+}
diff --git a/usr/src/slowsys/sys/trap.c b/usr/src/slowsys/sys/trap.c
new file mode 100644 (file)
index 0000000..ac5d34b
--- /dev/null
@@ -0,0 +1,150 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/reg.h"
+#include "../h/seg.h"
+#include "../h/trap.h"
+#include "../h/psl.h"
+
+#define        USER    040             /* user-mode flag added to type */
+
+struct sysent  sysent[64];
+
+/*
+ * Called from the trap handler when a processor trap occurs.
+ */
+trap(params, r0, r1, r2, r3, r4, r5 ,r6, r7, r8, r9, r10,
+       r11, r12, r13, sp, type, code, pc, psl)
+caddr_t params;
+{
+       register i, a;
+       register struct sysent *callp;
+       register caddr_t errorp;
+       register time_t syst;
+       register int *locr0;
+
+       locr0 = &r0;
+       syst = u.u_stime;
+       u.u_ar0 = locr0;
+       if (USERMODE(locr0[PS]))
+               type |= USER;
+       u.u_ar0 = locr0;
+       switch (type) {
+
+       /*
+        * Trap not expected.
+        * Usually a kernel mode bus error.
+        */
+       default:
+               printf("user = %x\n", ctob(u.u_procp->p_addr + 1));
+               printf("ps = %x\n", locr0[PS]);
+               printf("pc = %x\n", locr0[PC]);
+               printf("trap type %x\n", type);
+               printf("code = %x\n", code);
+               panic("trap");
+
+       case PROTFLT + USER:    /* protection fault */
+               i = SIGBUS;
+               break;
+
+       case PRIVINFLT + USER:  /* privileged instruction fault */
+       case RESADFLT + USER:   /* reserved addressing fault */
+       case RESOPFLT + USER:   /* resereved operand fault */
+               i = SIGINS;
+               break;
+
+       case RESCHED + USER:    /* Allow process switch */
+               goto out;
+
+       case SYSCALL + USER: /* sys call */
+               params += NBPW;         /* skip word with param count */
+               u.u_error = 0;
+               callp = &sysent[code&077];
+               if (callp == sysent) { /* indirect */
+                       a = fuword(params);
+                       params += NBPW;
+                       callp = &sysent[a&077];
+               }
+               for(i=0; i<callp->sy_narg; i++) {
+                       u.u_arg[i] = fuword(params);
+                       params += NBPW;
+               }
+               u.u_ap = u.u_arg;
+               locr0[PS] &= ~PSL_C;
+               u.u_dirp = (caddr_t)u.u_arg[0];
+               u.u_r.r_val1 = 0;
+               u.u_r.r_val2 = locr0[R1];
+               if(save(u.u_qsav)){
+                       if(u.u_error==0)
+                               u.u_error = EINTR;
+               } else {
+                       (*(callp->sy_call))();
+               }
+               if(u.u_error) {
+                       locr0[R0] = u.u_error;
+                       locr0[PS] |= PSL_C;     /* carry bit */
+                } else {
+                       locr0[R0] = u.u_r.r_val1;
+                       locr0[R1] = u.u_r.r_val2;
+               }
+               goto out;
+
+       case ARITHTRAP + USER:
+               i = SIGFPT;
+               break;
+
+       /*
+        * If the user SP is above the stack segment,
+        * grow the stack automatically.
+        */
+       case SEGFLT + USER: /* segmentation exception */
+               if(grow(locr0[SP]) || grow(code))
+                       goto out;
+               i = SIGSEG;
+               break;
+
+       case BPTFLT + USER:     /* bpt instruction fault */
+       case TRCTRAP + USER:    /* trace trap */
+               locr0[PS] &= ~PSL_T;    /* turn off trace bit */
+               i = SIGTRC;
+               break;
+
+       case XFCFLT + USER:     /* xfc instruction fault */
+               i = SIGEMT;
+               break;
+
+       }
+       psignal(u.u_procp, i);
+
+out:
+       if(issig())
+               psig();
+       curpri = setpri(u.u_procp);
+       if (runrun)
+               qswtch();
+       if(u.u_prof.pr_scale)
+               addupc((caddr_t)locr0[PC], &u.u_prof, (int)(u.u_stime-syst));
+       return;
+}
+
+/*
+ * nonexistent system call-- set fatal error code.
+ */
+nosys()
+{
+       u.u_error = 100;
+}
+
+/*
+ * Ignored system call
+ */
+nullsys()
+{
+}
+
+random(dev, stat, ps, pc, ccb)
+{
+       printf("Random interrupt, device %x\n", dev);
+}
diff --git a/usr/src/slowsys/sys/tty.c b/usr/src/slowsys/sys/tty.c
new file mode 100644 (file)
index 0000000..ec18108
--- /dev/null
@@ -0,0 +1,598 @@
+#
+/*
+ * general TTY subroutines
+ */
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/tty.h"
+#include "../h/proc.h"
+#include "../h/mx.h"
+#include "../h/inode.h"
+#include "../h/file.h"
+#include "../h/reg.h"
+#include "../h/conf.h"
+
+char   partab[];
+
+/*
+ * Input mapping table-- if an entry is non-zero, when the
+ * corresponding character is typed preceded by "\" the escape
+ * sequence is replaced by the table value.  Mostly used for
+ * upper-case only terminals.
+ */
+char   maptab[] =
+{
+       000,000,000,000,CEOT,00,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,'|',000,000,000,000,000,'`',
+       '{','}',000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,000,000,
+       000,000,000,000,000,000,'~',000,
+       000,'A','B','C','D','E','F','G',
+       'H','I','J','K','L','M','N','O',
+       'P','Q','R','S','T','U','V','W',
+       'X','Y','Z',000,000,000,000,000,
+};
+
+/*
+ * routine called on first teletype open.
+ * establishes a process group for distribution
+ * of quits and interrupts from the tty.
+ */
+ttyopen(dev, tp)
+dev_t dev;
+register struct tty *tp;
+{
+       register struct proc *pp;
+
+       pp = u.u_procp;
+       if(pp->p_pgrp == 0) {
+               u.u_ttyp = tp;
+               u.u_ttyd = dev;
+               if (tp->t_pgrp==0)
+                       tp->t_pgrp = pp->p_pid;
+               pp->p_pgrp = tp->t_pgrp;
+       }
+       tp->t_state &= ~WOPEN;
+       tp->t_state |= ISOPEN;
+}
+
+/*
+ * clean tp on last close
+ */
+ttyclose(tp)
+register struct tty *tp;
+{
+
+       tp->t_pgrp = 0;
+       wflushtty(tp);
+       tp->t_state = 0;
+}
+
+/*
+ * stty/gtty writearound
+ */
+stty()
+{
+       u.u_arg[2] = u.u_arg[1];
+       u.u_arg[1] = TIOCSETP;
+       ioctl();
+}
+
+gtty()
+{
+       u.u_arg[2] = u.u_arg[1];
+       u.u_arg[1] = TIOCGETP;
+       ioctl();
+}
+
+/*
+ * ioctl system call
+ * Check legality, execute common code, and switch out to individual
+ * device routine.
+ */
+ioctl()
+{
+       register struct file *fp;
+       register struct inode *ip;
+       register struct a {
+               int     fdes;
+               int     cmd;
+               caddr_t cmarg;
+       } *uap;
+       register dev_t dev;
+       register fmt;
+
+       uap = (struct a *)u.u_ap;
+       if ((fp = getf(uap->fdes)) == NULL)
+               return;
+       if (uap->cmd==FIOCLEX) {
+               u.u_pofile[uap->fdes] |= EXCLOSE;
+               return;
+       }
+       if (uap->cmd==FIONCLEX) {
+               u.u_pofile[uap->fdes] &= ~EXCLOSE;
+               return;
+       }
+       ip = fp->f_inode;
+       fmt = ip->i_mode & IFMT;
+       if (fmt != IFCHR && fmt != IFMPC) {
+               u.u_error = ENOTTY;
+               return;
+       }
+       dev = (dev_t)ip->i_un.i_rdev;
+       (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, fp->f_flag&(FREAD|FWRITE));
+}
+
+/*
+ * Common code for several tty ioctl commands
+ */
+ttioccomm(com, tp, addr, dev)
+register struct tty *tp;
+caddr_t addr;
+{
+       unsigned t;
+       struct ttiocb iocb;
+       extern int nldisp;
+
+       switch(com) {
+
+       /*
+        * get discipline number
+        */
+       case TIOCGETD:
+               t = tp->t_line;
+               if (copyout((caddr_t)&t, addr, sizeof(t)))
+                       u.u_error = EFAULT;
+               break;
+
+       /*
+        * set line discipline
+        */
+       case TIOCSETD:
+               if (copyin(addr, (caddr_t)&t, sizeof(t))) {
+                       u.u_error = EFAULT;
+                       break;
+               }
+               if (t >= nldisp) {
+                       u.u_error = ENXIO;
+                       break;
+               }
+               if (tp->t_line)
+                       (*linesw[tp->t_line].l_close)(tp);
+               if (t)
+                       (*linesw[t].l_open)(dev, tp, addr);
+               if (u.u_error==0)
+                       tp->t_line = t;
+               break;
+
+       /*
+        * prevent more opens on channel
+        */
+       case TIOCEXCL:
+               tp->t_state |= XCLUDE;
+               break;
+       case TIOCNXCL:
+               tp->t_state &= ~XCLUDE;
+               break;
+
+       /*
+        * Set new parameters
+        */
+       case TIOCSETP:
+               wflushtty(tp);
+       case TIOCSETN:
+               if (copyin(addr, (caddr_t)&iocb, sizeof(iocb))) {
+                       u.u_error = EFAULT;
+                       return(1);
+               }
+               tp->t_ispeed = iocb.ioc_ispeed;
+               tp->t_ospeed = iocb.ioc_ospeed;
+               tp->t_erase = iocb.ioc_erase;
+               tp->t_kill = iocb.ioc_kill;
+               tp->t_flags = iocb.ioc_flags;
+               break;
+
+       /*
+        * send current parameters to user
+        */
+       case TIOCGETP:
+               iocb.ioc_ispeed = tp->t_ispeed;
+               iocb.ioc_ospeed = tp->t_ospeed;
+               iocb.ioc_erase = tp->t_erase;
+               iocb.ioc_kill = tp->t_kill;
+               iocb.ioc_flags = tp->t_flags;
+               if (copyout((caddr_t)&iocb, addr, sizeof(iocb)))
+                       u.u_error = EFAULT;
+               break;
+
+       /*
+        * Hang up line on last close
+        */
+
+       case TIOCHPCL:
+               tp->t_state |= HUPCLS;
+               break;
+
+       /*
+        * ioctl entries to line discipline
+        */
+       case DIOCSETP:
+       case DIOCGETP:
+               (*linesw[tp->t_line].l_ioctl)(com, tp, addr);
+               break;
+       default:
+               return(0);
+       }
+       return(1);
+}
+
+/*
+ * Wait for output to drain, then flush input waiting.
+ */
+wflushtty(tp)
+register struct tty *tp;
+{
+
+       spl5();
+       while (tp->t_outq.c_cc && tp->t_state&CARR_ON) {
+               (*tp->t_oproc)(tp);
+               tp->t_state |= ASLEEP;
+               sleep((caddr_t)&tp->t_outq, TTOPRI);
+       }
+       flushtty(tp);
+       spl0();
+}
+
+/*
+ * flush all TTY queues
+ */
+flushtty(tp)
+register struct tty *tp;
+{
+       register s;
+
+       while (getc(&tp->t_canq) >= 0)
+               ;
+       while (getc(&tp->t_outq) >= 0)
+               ;
+       wakeup((caddr_t)&tp->t_rawq);
+       wakeup((caddr_t)&tp->t_outq);
+       s = spl5();
+       while (getc(&tp->t_rawq) >= 0)
+               ;
+       tp->t_delct = 0;
+       splx(s);
+}
+
+/*
+ * transfer raw input list to canonical list,
+ * doing erase-kill processing and handling escapes.
+ * It waits until a full line has been typed in cooked mode,
+ * or until any character has been typed in raw mode.
+ */
+canon(tp)
+register struct tty *tp;
+{
+       register char *bp;
+       char *bp1;
+       register int c;
+       int mc;
+
+       spl5();
+       while ((tp->t_flags&(RAW|CBREAK))==0 && tp->t_delct==0
+           || (tp->t_flags&(RAW|CBREAK))!=0 && tp->t_rawq.c_cc==0) {
+               if ((tp->t_state&CARR_ON)==0)
+                       return(0);
+               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+       }
+       spl0();
+loop:
+       bp = &canonb[2];
+       while ((c=getc(&tp->t_rawq)) >= 0) {
+               if ((tp->t_flags&(RAW|CBREAK))==0) {
+                       if (c==0377) {
+                               tp->t_delct--;
+                               break;
+                       }
+                       if (bp[-1]!='\\') {
+                               if (c==tp->t_erase) {
+                                       if (bp > &canonb[2])
+                                               bp--;
+                                       continue;
+                               }
+                               if (c==tp->t_kill)
+                                       goto loop;
+                               if (c==CEOT)
+                                       continue;
+                       } else {
+                               mc = maptab[c];
+                               if (c==tp->t_erase || c==tp->t_kill)
+                                       mc = c;
+                               if (mc && (mc==c || (tp->t_flags&LCASE))) {
+                                       if (bp[-2] != '\\')
+                                               c = mc;
+                                       bp--;
+                               }
+                       }
+               }
+               *bp++ = c;
+               if (bp>=canonb+CANBSIZ)
+                       break;
+       }
+       bp1 = bp;
+       bp = &canonb[2];
+       while (bp<bp1)
+               putc(*bp++, &tp->t_canq);
+       return(bp1 - &canonb[2]);
+}
+
+/*
+ * Place a character on raw TTY input queue, putting in delimiters
+ * and waking up top half as needed.
+ * Also echo if required.
+ * The arguments are the character and the appropriate
+ * tty structure.
+ */
+ttyinput(c, tp)
+register c;
+register struct tty *tp;
+{
+       register int t_flags;
+       register struct chan *cp;
+
+       tk_nin += 1;
+       c &= 0377;
+       t_flags = tp->t_flags;
+       if ((t_flags&RAW)==0) {
+               c &= 0177;
+               if (c==CSTOP) {
+                       tp->t_state ^= TTSTOP;
+                       ttstart(tp);
+                       return;
+               }
+               tp->t_state &= ~TTSTOP;
+               if (c==CQUIT || c==CINTR) {
+                       signal(tp->t_pgrp, c==CINTR? SIGINT:SIGQUIT);
+                       flushtty(tp);
+                       return;
+               }
+               if (c=='\r' && t_flags&CRMOD)
+                       c = '\n';
+       }
+       if (tp->t_rawq.c_cc>TTYHOG) {
+               flushtty(tp);
+               return;
+       }
+       if (t_flags&LCASE && c>='A' && c<='Z')
+               c += 'a'-'A';
+       putc(c, &tp->t_rawq);
+       if (t_flags&(RAW|CBREAK) || (c=='\n' || c==CEOT)) {
+               if ((t_flags&(RAW|CBREAK))==0 && putc(0377, &tp->t_rawq)==0)
+                       tp->t_delct++;
+               if (cp = tp->t_chan)
+                       sdata(cp);
+               else
+                       wakeup((caddr_t)&tp->t_rawq);
+       }
+       if (t_flags&ECHO) {
+               ttyoutput(c, tp);
+               if (c==tp->t_kill && (t_flags&(RAW|CBREAK))==0)
+                       ttyoutput('\n', tp);
+               ttstart(tp);
+       }
+}
+
+/*
+ * put character on TTY output queue, adding delays,
+ * expanding tabs, and handling the CR/NL bit.
+ * It is called both from the top half for output, and from
+ * interrupt level for echoing.
+ * The arguments are the character and the tty structure.
+ */
+ttyoutput(c, tp)
+register c;
+register struct tty *tp;
+{
+       register char *colp;
+       register ctype;
+
+       tk_nout += 1;
+       /*
+        * Ignore EOT in normal mode to avoid hanging up
+        * certain terminals.
+        * In raw mode dump the char unchanged.
+        */
+
+       if ((tp->t_flags&RAW)==0) {
+               c &= 0177;
+               if (c==CEOT)
+                       return;
+       } else {
+               putc(c, &tp->t_outq);
+               return;
+       }
+       /*
+        * Turn tabs to spaces as required
+        */
+       if (c=='\t' && (tp->t_flags&TBDELAY)==XTABS) {
+               c = 8;
+               do
+                       ttyoutput(' ', tp);
+               while (--c >= 0 && tp->t_col&07);
+               return;
+       }
+       /*
+        * for upper-case-only terminals,
+        * generate escapes.
+        */
+       if (tp->t_flags&LCASE) {
+               colp = "({)}!|^~'`";
+               while(*colp++)
+                       if(c == *colp++) {
+                               ttyoutput('\\', tp);
+                               c = colp[-2];
+                               break;
+                       }
+               if ('a'<=c && c<='z')
+                       c += 'A' - 'a';
+       }
+       /*
+        * turn <nl> to <cr><lf> if desired.
+        */
+       if (c=='\n' && tp->t_flags&CRMOD)
+               ttyoutput('\r', tp);
+       putc(c, &tp->t_outq);
+       /*
+        * Calculate delays.
+        * The numbers here represent clock ticks
+        * and are not necessarily optimal for all terminals.
+        * The delays are indicated by characters above 0200.
+        * In raw mode there are no delays and the
+        * transmission path is 8 bits wide.
+        */
+       colp = &tp->t_col;
+       ctype = partab[c];
+       c = 0;
+       switch (ctype&077) {
+
+       /* ordinary */
+       case 0:
+               (*colp)++;
+
+       /* non-printing */
+       case 1:
+               break;
+
+       /* backspace */
+       case 2:
+               if (*colp)
+                       (*colp)--;
+               break;
+
+       /* newline */
+       case 3:
+               ctype = (tp->t_flags >> 8) & 03;
+               if(ctype == 1) { /* tty 37 */
+                       if (*colp)
+                               c = max(((unsigned)*colp>>4) + 3, (unsigned)6);
+               } else
+               if(ctype == 2) { /* vt05 */
+                       c = 6;
+               }
+               *colp = 0;
+               break;
+
+       /* tab */
+       case 4:
+               ctype = (tp->t_flags >> 10) & 03;
+               if(ctype == 1) { /* tty 37 */
+                       c = 1 - (*colp | ~07);
+                       if(c < 5)
+                               c = 0;
+               }
+               *colp |= 07;
+               (*colp)++;
+               break;
+
+       /* vertical motion */
+       case 5:
+               if(tp->t_flags & VTDELAY) /* tty 37 */
+                       c = 0177;
+               break;
+
+       /* carriage return */
+       case 6:
+               ctype = (tp->t_flags >> 12) & 03;
+               if(ctype == 1) { /* tn 300 */
+                       c = 5;
+               } else if(ctype == 2) { /* ti 700 */
+                       c = 10;
+               }
+               *colp = 0;
+       }
+       if(c)
+               putc(c|0200, &tp->t_outq);
+}
+
+/*
+ * Restart typewriter output following a delay
+ * timeout.
+ * The name of the routine is passed to the timeout
+ * subroutine and it is called during a clock interrupt.
+ */
+ttrstrt(tp)
+register struct tty *tp;
+{
+
+       tp->t_state &= ~TIMEOUT;
+       ttstart(tp);
+}
+
+/*
+ * Start output on the typewriter. It is used from the top half
+ * after some characters have been put on the output queue,
+ * from the interrupt routine to transmit the next
+ * character, and after a timeout has finished.
+ */
+ttstart(tp)
+register struct tty *tp;
+{
+       register s;
+
+       s = spl5();
+       if((tp->t_state&(TIMEOUT|TTSTOP|BUSY)) == 0)
+               (*tp->t_oproc)(tp);
+       splx(s);
+}
+
+/*
+ * Called from device's read routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttread(tp)
+register struct tty *tp;
+{
+       struct chan *chan;
+
+       if ((tp->t_state&CARR_ON)==0)
+               return;
+       chan = tp->t_chan;
+       tp->t_chan = NULL;
+       if (tp->t_canq.c_cc || canon(tp))
+               while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0)
+                       ;
+       tp->t_chan = chan;
+}
+
+/*
+ * Called from the device's write routine after it has
+ * calculated the tty-structure given as argument.
+ */
+ttwrite(tp)
+register struct tty *tp;
+{
+       register c;
+
+       if ((tp->t_state&CARR_ON)==0)
+               return;
+       while ((c=cpass())>=0) {
+               spl5();
+               while (tp->t_outq.c_cc > TTHIWAT) {
+                       ttstart(tp);
+                       tp->t_state |= ASLEEP;
+                       sleep((caddr_t)&tp->t_outq, TTOPRI);
+               }
+               spl0();
+               ttyoutput(c, tp);
+       }
+       ttstart(tp);
+}
diff --git a/usr/src/slowsys/sys/uba.c b/usr/src/slowsys/sys/uba.c
new file mode 100644 (file)
index 0000000..e93e39a
--- /dev/null
@@ -0,0 +1,107 @@
+# include "../h/param.h"
+#include "../h/uba.h"
+# include "../h/map.h"
+int uballoc(baddr,bcnt,bdpflg)
+char  bdpflg ;
+char * baddr ;
+unsigned short bcnt;
+{
+/*
+*  Allocate as many contiguous UBA mapping registers
+*  as are necessary to do transfer of 'bcnt' bytes
+*  to/from location 'baddr'.
+*  Wait for enough map registers.
+*  'bdpflg' is non-zero if a "buffered data path" (BDP) is
+*  to be used, else 0 -> use direct data path (DDP) .
+*  Return
+*
+*    |31 - - 28|27 - - 18|17 - - - 9|8 - - 0|
+*    |         |         |          |       |
+*    |  BDP    |   no.   |  start   | byte  |
+*    |   no.   | mapping |   map    | offset|
+*    |         |  reg's  | reg. no. |       |
+*    |         |         |          |       |
+*
+*/
+register regnum , nmreg , bdp , pfn , j ;
+/* calculate no. of mapping reg's required */
+nmreg = btoc(bcnt) + 2;
+pfn = ((int)baddr>>9) & 0xfff ; /* start page frame no. */
+spl6() ;
+while ((regnum = malloc(ubamap,nmreg) - 1) < 0) {
+       /* wait for no. of mapping reg's requested */
+       umrwant++ ;
+       sleep(ubamap,PSWP) ;
+       }
+if (bdpflg)  /* buffered data path BDP 1-15 */
+       while ( (bdp=malloc(bdpmap,1)) == NULL)
+               {
+               bdpwant++;
+               sleep(bdpmap, PSWP);
+               }
+else { /* BDP 0 = DDP */
+       bdp = 0 ;
+       }
+spl0() ;
+j = (bdp<<28) | (nmreg<<18) | (regnum<<9) | ((int)baddr & 0x01ff) ;
+pfn |= (MRV | (bdp<<21)) ; /* map reg entry */
+if (bdp && ((int)baddr & 01)) pfn |= BO ; /* byte offset */
+while (--nmreg)  /* fill the memory mapping reg's */
+       ((struct uba_regs *)UBA0)->uba_map[regnum++] = pfn++ ;
+((struct uba_regs *)UBA0)->uba_map[regnum] = 0 ; /* last entry is invalid */
+return(j) ;
+}
+/*                                                     */
+ubafree(mr)
+int mr ;
+{
+/*
+*  Free UBA memory mapping reg's and a BDP no..
+*    mr :
+*              bits 0 - 3 :  bdp no.
+*               4 - 15 : start map reg. no.
+*                      16 - 31 : no. of mapping reg's
+*
+*/
+register bdp , nmreg , regnum ;
+spl6();
+bdp = (mr>>28) & 0x0f ;  /* BDP no. */
+if (bdp)
+       {
+       ((struct uba_regs *)UBA0)->uba_dpr[bdp] |= BNE ; /* purge */
+       mfree(bdpmap, 1, bdp);
+       if (bdpwant) {
+               bdpwant = 0;
+               wakeup(bdpmap);
+       }
+}
+
+nmreg = (mr>>18) & 0x3ff ; /* no. of mapping reg's */
+regnum = (mr>>9) & 0x1ff ; /* 1st map reg. no. */
+/* free mapping reg's */
+mfree(ubamap,nmreg,regnum+1) ;
+if (umrwant) {
+       umrwant = 0;
+       wakeup(ubamap);
+}
+spl0() ;
+}
+
+ubainit()
+{
+       mfree(ubamap, 496, 1);
+       mfree(bdpmap, 15, 1);
+}
diff --git a/usr/src/slowsys/sys/ureg.c b/usr/src/slowsys/sys/ureg.c
new file mode 100644 (file)
index 0000000..0a5be2d
--- /dev/null
@@ -0,0 +1,88 @@
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/text.h"
+#include "../h/seg.h"
+#include "../h/mtpr.h"
+#include "../h/page.h"
+
+/*
+ * Create absolutized user-map
+ * register image from the software prototype.
+ * The software registers must have
+ * been setup prior by estabur.
+ */
+sureg()
+{
+       register int tpfnum, dpfnum;
+       register struct pt_entry *ptaddr, *end_ptaddr;
+       struct text *tp;
+
+       ptaddr = (struct pt_entry *)mfpr(P0BR);
+       tpfnum = dpfnum = u.u_procp->p_addr + USIZE;
+       if ((tp=u.u_procp->p_textp) != NULL)
+               tpfnum = tp->x_caddr;
+       end_ptaddr = (struct pt_entry *)(((int)ptaddr) + u.u_pcb.pcb_szpt*512);
+
+       do
+               ptaddr->pg_pfnum = (ptaddr->pg_v ? ((*(int *)ptaddr)&PG_TXT ? tpfnum++ : dpfnum++) : 0);
+       while ( ++ptaddr < end_ptaddr);
+
+       mtpr(P0LR, u.u_pcb.pcb_p0lr & 0xffffff);        /* set seg 0 size */
+       mtpr(P1LR, u.u_pcb.pcb_p1lr);
+       mtpr(TBIA,1);           /* conserative */
+}
+
+/*
+ * Set up software prototype segmentation
+ * registers to implement the 3 pseudo
+ * text,data,stack segment sizes passed
+ * as arguments.
+ * The argument sep specifies if the
+ * text and data+stack segments are to
+ * be separated.
+ * (Not possible on Interdata)
+ * The last argument determines whether the text
+ * segment is read-write or read-only.
+ */
+estabur(nt, nd, ns, sep, xrw)
+register int nt, nd, ns;
+{
+       register *a, *ap;
+       int nnt, nnd, nns;
+
+       nnt = nt;
+       nnd = nd;
+       nns = ns;
+       if(ctos(nt)+ctos(nd)+ctos(ns) > u.u_pcb.pcb_szpt*128)
+               goto err;
+       if(nt+nd+ns+USIZE > maxmem)
+               goto err;
+       ap = (int *)mfpr(P0BR);
+       a = (int *)(((int)ap) + u.u_pcb.pcb_szpt*512 - ns*4);
+       while(nt > 0) {
+               *ap++ = PG_V | PG_TXT | xrw ;
+               nt--;
+       }
+       while(nd > 0) {
+               *ap++ = PG_V | RW ;
+               nd--;
+       }
+       while(ap < a) {
+               *ap++ = RW;
+       }
+       while(ns > 0) {
+               *ap++ = PG_V | RW ;
+               ns--;
+       }
+       u.u_pcb.pcb_p0lr = 0x4000000 | (nnt + nnd);
+       u.u_pcb.pcb_p1lr = 0x200000 - nns;
+       sureg();
+       return(0);
+
+err:
+       u.u_error = ENOMEM;
+       return(-1);
+}
diff --git a/usr/src/slowsys/sys/v45lnk.c b/usr/src/slowsys/sys/v45lnk.c
new file mode 100644 (file)
index 0000000..cbd7940
--- /dev/null
@@ -0,0 +1,216 @@
+# include "../h/param.h"
+# include "../h/dir.h"
+# include "../h/user.h"
+# include "../h/proc.h"
+# include "../h/uba.h"
+# include "../h/buf.h"
+/*             */
+# define LNKADR (UBA0_DEV+0172410) /* DR11-B devive reg's */
+/*
+*  UBA0_DEV = 0x80018000
+*  LNKADR = 0x80027508
+*/
+/*  DA11-B  DR-11B Status & Command reg */
+# define ERR  0x8000  /*  error bit */
+# define NEX  0x4000  /*  non-existent memory */
+# define IIR  0x800  /*  Input Interrupt Request */
+# define ID  0x400  /*  Input direction */
+# define IM  0x200  /*  Input mode */
+# define CYCLE  0x100  /* Cycle */
+# define RDY  0x80  /* Ready */
+# define IE  0x40  /*  Interrupt Enable */
+# define OIR  8  /*  Output interrupt request */
+# define OD  4  /* Output direction */
+# define OM  2  /* output mode */
+# define GO  1  /* Go bit */
+/*     states  */
+# define CLOSED 0  /*  closed */
+# define  OPEN  1  /* open  */
+# define  S1  2  /* write state 1 */
+# define  S2  4  /* write state 2 */
+# define  R1  8  /* read state 1 */
+# define  R2  16  /* read state 2 */
+# define L_NOT 128  /*  send OIR to other end link */
+# define IPEND 256
+# define PREread  512  /*  'lnkmon' wait */
+# define L_MON 1024  /* 'lnkmon' decr V11opn */
+# define L_WAKE  2048
+# define BUSY (S1|S2|R1|R2)  /* i-o in progress for driver */
+# define S_ERR  0x8000
+/*             */
+# define  V11PRI  0
+# define BUFSIZ  512
+# define VSPEC  0100000
+/*             */
+struct lnkreg {
+       short drwc , drba , drst , drdb ;
+       } ;
+struct {
+       short state ;
+       struct buf *bp ;
+       } V11tab ;
+char V11opn ;
+/*             */
+V11open(dev,flag)
+{
+struct buf *geteblk() ;
+if (V11opn) {
+       u.u_error = EBUSY;
+       return;
+       }
+V11opn++;
+if (V11tab.bp == 0) /* grab system buffer */
+       V11tab.bp = geteblk() ;  /*  VAX call */
+((struct lnkreg *)LNKADR)->drst |= IE ;
+V11tab.state |= OPEN ;
+}
+/*             */
+V11close(dev,flag) /* called on last close only ! ! */
+{
+V11opn = 0;
+V11tab.state = CLOSED ;
+((struct lnkreg *)LNKADR)->drst = 0 ; /* IE off */
+if (V11tab.bp) brelse(V11tab.bp) ; /* release system buffer */
+V11tab.bp = 0 ;
+}
+/*             */
+V11write(dev)
+{
+register int i , j  , k ;
+/*  INIT clears OUTPUT DIR bit = transmitter */
+spl5() ;
+V11tab.state |= S1 ;
+/* setup for transmit */
+((struct lnkreg *)LNKADR)->drst &= ~(OD) ; /* 0 -> transmitter */
+spl0() ;
+i = uballoc(V11tab.bp->b_un.b_addr,BUFSIZ,1) ; /* get UBA map entry for
+       system buffer and set valid bit & BDP no. & BO bit & load map */
+j = i & 0x3ffff ; /* start map no. & byte offset */
+/* write loop, until done or error */
+while ((u.u_count > 0) && (u.u_error == 0)) {
+       iomove(V11tab.bp->b_un.b_addr,min(BUFSIZ,u.u_count),B_WRITE) ; /* move
+               data from user space to system buffer */
+       ((struct lnkreg *)LNKADR)->drwc = (-(BUFSIZ>>1)) ; /* word count */
+       ((struct lnkreg *)LNKADR)->drba = j ; /* map no. (SBI page) & byte offset */
+       spl5() ;
+       ((struct lnkreg *)LNKADR)->drst |= GO ; /* setup for transfer */
+       sleep(LNKADR,V11PRI) ; /* wait for transfer to finish(interrupt) */
+       spl0() ;
+       if (V11tab.state & S_ERR)
+               u.u_error = ENXIO ;
+       }
+ubafree(i) ;
+((struct lnkreg *)LNKADR)->drst &= (~OM);
+V11tab.state &= (~BUSY) ;
+}
+/*             */
+V11read(dev)
+{
+register i , j  ;
+spl5() ;
+V11tab.state |= R1 ;
+((struct lnkreg *)LNKADR)->drst |= OD ; /* receiver */
+spl0() ;
+i = uballoc(V11tab.bp->b_un.b_addr,BUFSIZ,1) ;
+j = i & 0x3ffff ; /* start map no. & byte offset */
+while ((u.u_count>0) && (u.u_error == 0)) {
+       ((struct lnkreg *)LNKADR)->drwc = (-(BUFSIZ>>1)) ;
+       ((struct lnkreg *)LNKADR)->drba = j ;
+       spl5() ;
+       ((struct lnkreg *)LNKADR)->drst |= GO ;
+       /* wait for i-o to finish */
+       sleep(LNKADR,V11PRI) ;
+       spl0() ;
+       if (V11tab.state & S_ERR) {
+               u.u_error = ENXIO ;
+               continue ;
+               }
+       iomove(V11tab.bp->b_un.b_addr,min(BUFSIZ,u.u_count),B_READ) ;
+       }
+ubafree(i) ;
+V11tab.state &= (~BUSY) ;
+}
+/*             */
+V11int(dev)
+{
+register unsigned short state ;
+register int i ;
+extern int V11ioctl() ;
+if ((i = ((struct lnkreg *)LNKADR)->drst) & ERR)
+       V11tab.state |= S_ERR ;
+state = V11tab.state ;
+if (state&BUSY) {
+       wakeup(LNKADR) ;
+       return ;
+       }
+if (i&IM) {
+       if (state&PREread) {
+               wakeup(V11ioctl);
+               return;
+               }
+       if (((state&BUSY) == 0) && (state&OPEN))
+               V11tab.state |= IPEND ;
+       return;
+       }
+}
+/*             */
+V11ioctl(dev,cmd,addr,flag)
+dev_t dev;
+caddr_t addr;
+{
+if (cmd & VSPEC) {
+       switch (cmd & 077777) {
+               case L_WAKE : { /* debug wakeup */
+                       wakeup(LNKADR);
+                       break;
+                       }
+               case L_NOT : { /* send OIR to other end of link */
+                       spl5();
+                       ((struct lnkreg *)LNKADR)->drst |= (OIR|OM) ;
+                       ((struct lnkreg *)LNKADR)->drst &= (~OIR);
+                       spl0();
+                       break;
+                       }
+               case L_MON : { /* 'lnkmon' decr 'V11opn' */
+                       V11opn--;
+                       break;
+                       }
+               case PREread : { /* 'lnkmon' wait */
+                       spl5();
+                       if (V11tab.state&IPEND) {
+                               V11tab.state &= (~IPEND);
+                               }
+                       else {
+                               V11tab.state |= PREread;
+                               sleep(V11ioctl,PZERO+1);
+                               V11tab.state &= (~PREread);
+                               }
+                       spl0();
+                       break;
+                       }
+               }
+       }
+else {
+       *((short *)addr) = V11tab.state;
+       }
+}