BSD 4 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Sun, 9 Nov 1980 10:35:33 +0000 (02:35 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Sun, 9 Nov 1980 10:35:33 +0000 (02:35 -0800)
Work on file usr/src/sys/sys/clock.c
Work on file usr/src/sys/sys/alloc.c
Work on file usr/src/sys/sys/vmsys.c
Work on file usr/src/sys/sys/fio.c
Work on file usr/src/sys/sys/iget.c
Work on file usr/src/sys/sys/malloc.c
Work on file usr/src/sys/sys/partab.c
Work on file usr/src/sys/sys/prim.c
Work on file usr/src/sys/sys/subr.c
Work on file usr/src/sys/sys/swtch.c
Work on file usr/src/sys/sys/sys.c
Work on file usr/src/sys/sys/sys3.c
Work on file usr/src/sys/sys/sysent.c
Work on file usr/src/sys/sys/sys4.c
Work on file usr/src/sys/sys/text.c
Work on file usr/src/sys/sys/vmdrum.c
Work on file usr/src/sys/sys/vmmon.c
Work on file usr/src/sys/sys/vmsched.c
Work on file usr/src/sys/sys/vmsysent.c
Work on file usr/src/sys/sys/TODO
Work on file usr/src/sys/sys/asm.sed

Synthesized-from: CSRG//cd1/4.0

21 files changed:
usr/src/sys/sys/TODO [new file with mode: 0644]
usr/src/sys/sys/alloc.c [new file with mode: 0644]
usr/src/sys/sys/asm.sed [new file with mode: 0644]
usr/src/sys/sys/clock.c [new file with mode: 0644]
usr/src/sys/sys/fio.c [new file with mode: 0644]
usr/src/sys/sys/iget.c [new file with mode: 0644]
usr/src/sys/sys/malloc.c [new file with mode: 0644]
usr/src/sys/sys/partab.c [new file with mode: 0644]
usr/src/sys/sys/prim.c [new file with mode: 0644]
usr/src/sys/sys/subr.c [new file with mode: 0644]
usr/src/sys/sys/swtch.c [new file with mode: 0644]
usr/src/sys/sys/sys.c [new file with mode: 0644]
usr/src/sys/sys/sys3.c [new file with mode: 0644]
usr/src/sys/sys/sys4.c [new file with mode: 0644]
usr/src/sys/sys/sysent.c [new file with mode: 0644]
usr/src/sys/sys/text.c [new file with mode: 0644]
usr/src/sys/sys/vmdrum.c [new file with mode: 0644]
usr/src/sys/sys/vmmon.c [new file with mode: 0644]
usr/src/sys/sys/vmsched.c [new file with mode: 0644]
usr/src/sys/sys/vmsys.c [new file with mode: 0644]
usr/src/sys/sys/vmsysent.c [new file with mode: 0644]

diff --git a/usr/src/sys/sys/TODO b/usr/src/sys/sys/TODO
new file mode 100644 (file)
index 0000000..2703dfe
--- /dev/null
@@ -0,0 +1,33 @@
+/*     TODO    4.1     11/9/80 */
+
+1. Uba fixups
+       Add tm, rk, and lp driver to distribution system.
+       Add rk and tm to standalone system; tm tape bootstrap!
+       Clear errors on UBA SBI faults, print silo and continue
+
+2. Mba fixup.
+       Mostly from Jim Kulp; mba.c driver instead of devices dealing with
+       mba's.  Thus can run multiple mba's and mix devices on a single mba.
+
+3. Signal fixup
+       Change parameters passed when signal occurs to include additional
+       code (defined by K_ things in <signal.h> so a signal handler can
+       get all the machine status.).
+
+4. Pgrp fixups
+       Hash the process groups in the proc table so wakeups are fast
+       e.g. with SIGTTIN and tty signals.
+
+5. Disk drive fixes
+       Dont search if only one drive is active thereby saving half the
+       interrupts.
+
+6. Exec fixes
+       Implement dmr's #! feature; pass string arguments through faster.
+
+7. Reboot fixups
+       Support automatic dumps to paging area
+
+8. Memory controller monitoring
+       Monitor two memory controllers if there are 2 in the machine.
+       Support interleaved memory
diff --git a/usr/src/sys/sys/alloc.c b/usr/src/sys/sys/alloc.c
new file mode 100644 (file)
index 0000000..e6cbe97
--- /dev/null
@@ -0,0 +1,381 @@
+/*     alloc.c 4.1     11/9/80 */
+
+#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);
+
+               /*
+                * Prevent ``dups in free''
+                */
+               bp = getblk(dev, SUPERB);
+               fp->s_fmod = 0;
+               fp->s_time = time;
+               bcopy((caddr_t)fp, bp->b_un.b_addr, BSIZE);
+               bwrite(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;
+       fp->s_tfree--;
+       return(bp);
+
+nospace:
+       fp->s_nfree = 0;
+       fp->s_tfree = 0;
+       /* SHOULD PROBABLY HINDER THE ABILITY OF ONE PROCESS TO CAUSE THIS... */
+       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_tfree++;
+       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, inobas;
+       int first;
+       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;
+                       fp->s_tinode--;
+                       return(ip);
+               }
+               /*
+                * Inode was allocated after all.
+                * Look some more.
+                */
+               iput(ip);
+               goto loop;
+       }
+       fp->s_ilock++;
+#ifdef TRACEIA
+       printf("s_lasti %d, s_nbehind %d\n", fp->s_lasti, fp->s_nbehind);
+#endif
+       if (fp->s_nbehind < 4 * NICINOD) {
+               first = 1;
+               ino = fp->s_lasti;
+               if (itoo(ino))
+                       panic("ialloc");
+               adr = itod(ino);
+       } else {
+fromtop:
+               first = 0;
+               ino = 1;
+               adr = SUPERB+1;
+               fp->s_nbehind = 0;
+       }
+#ifdef TRACEIA
+       printf("searching %x/%x from %d\n", major(dev), minor(dev), ino);
+#endif
+       for(; adr < fp->s_isize; adr++) {
+               inobas = ino;
+               bp = bread(dev, adr);
+               if ((bp->b_flags&B_CACHE) == 0)
+                       u.u_vm.vm_inblk--;              /* no charge! */
+               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;
+                       if(ifind(dev, ino))
+                               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;
+       }
+       if (fp->s_ninode < NICINOD && first) {
+#ifdef TRACEIA
+               printf("found only %d inodes on dev %x/%x, looking from top\n",
+                   fp->s_ninode, major(dev), minor(dev));
+#endif
+               goto fromtop;
+       }
+#ifdef TRACEIA
+       printf("search of %x/%x ended at %d\n", major(dev), minor(dev), ino);
+#endif
+       fp->s_lasti = inobas;
+       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);
+       fp->s_tinode++;
+       if(fp->s_ilock)
+               return;
+       if(fp->s_ninode >= NICINOD) {
+               if (fp->s_lasti > ino)
+                       fp->s_nbehind++;
+               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);
+}
+
+getfsx(dev)
+dev_t dev;
+{
+       register struct mount *mp;
+
+       if (dev == swapdev)
+               return (MSWAPX);
+       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
+               if (mp->m_dev == dev)
+                       return (mp - &mount[0]);
+       return (-1);
+}
+
+/*
+ * 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);
+                       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, 0);
+                       iput(ip);
+               }
+       updlock = 0;
+       bflush(NODEV);
+}
diff --git a/usr/src/sys/sys/asm.sed b/usr/src/sys/sys/asm.sed
new file mode 100644 (file)
index 0000000..c8c86bb
--- /dev/null
@@ -0,0 +1,57 @@
+s,11/9/80 4.1 asm.sed,11/9/80 4.1 asm.sed,
+s/calls        $0,_spl0/mfpr   $18,r0\
+       mtpr    $0,$18/
+s/calls        $0,_spl1/mfpr   $18,r0\
+       mtpr    $2,$18/
+s/calls        $0,_spl4/mfpr   $18,r0\
+       mtpr    $0x14,$18/
+s/calls        $0,_spl5/mfpr   $18,r0\
+       mtpr    $0x15,$18/
+s/calls        $0,_spl6/mfpr   $18,r0\
+       mtpr    $0x18,$18/
+s/calls        $0,_spl7/mfpr   $18,r0\
+       mtpr    $0x18,$18/
+s/calls        $1,_splx/mfpr   $18,r0\
+       mtpr    (sp)+,$18/
+s/calls        $1,_mfpr/mfpr   (sp)+,r0/
+s/calls        $2,_mtpr/mtpr   4(sp),(sp)\
+       addl2   $8,sp/
+s/calls        $1,_resume/ashl $9,(sp)+,r0 \
+       movpsl  -(sp) \
+       jsb     _Resume/
+s/calls        $3,_bcopy/movc3 8(sp),*(sp),*4(sp)\
+       addl2   $12,sp/
+s/calls        $3,_copyin/jsb  _Copyin\
+       addl2   $12,sp/
+s/calls        $3,_copyout/jsb _Copyout\
+       addl2   $12,sp/
+s/calls        $1,_fubyte/movl (sp)+,r0 \
+       jsb     _Fubyte/
+s/calls        $1,_fuibyte/movl (sp)+,r0 \
+       jsb     _Fubyte/
+s/calls        $1,_fuword/movl (sp)+,r0 \
+       jsb     _Fuword/
+s/calls        $1,_fuiword/movl (sp)+,r0 \
+       jsb     _Fuword/
+s/calls        $2,_subyte/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Subyte/
+s/calls        $2,_suibyte/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Subyte/
+s/calls        $2,_suword/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Suword/
+s/calls        $2,_suiword/movl (sp)+,r0 \
+       movl    (sp)+,r1 \
+       jsb     _Suword/
+s/calls        $1,_setrq/movl  (sp)+,r0 \
+       jsb     _Setrq/
+s/calls        $1,_remrq/movl  (sp)+,r0 \
+       jsb     _Remrq/
+s/calls        $0,_swtch/movpsl        -(sp)\
+       jsb     _Swtch/
+s/calls        $1,_setjmp/movl (sp)+,r0 \
+       jsb     _Setjmp/
+s/calls        $1,_longjmp/movl        (sp)+,r0 \
+       jsb     _Longjmp/
diff --git a/usr/src/sys/sys/clock.c b/usr/src/sys/sys/clock.c
new file mode 100644 (file)
index 0000000..83a1d3e
--- /dev/null
@@ -0,0 +1,340 @@
+/*     11/9/80 4.1     clock.c */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dk.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"
+#include "../h/vm.h"
+#include "../h/buf.h"
+#include "../h/text.h"
+#include "../h/vlimit.h"
+#include "../h/mtpr.h"
+#include "../h/clock.h"
+
+#include "../conf/dh.h"
+#include "../conf/dz.h"
+
+#define        SCHMAG  9/10
+
+/*
+ * Constant for decay filter for cpu usage.
+ */
+double ccpu = 0.95122942450071400909;          /* exp(-1/20) */
+
+/*
+ * Clock is called straight from
+ * the real time clock interrupt.
+ *
+ * Functions:
+ *     implement callouts
+ *     maintain user/system times
+ *     maintain date
+ *     profile
+ *     lightning bolt wakeup (every second)
+ *     alarm clock signals
+ *     jab the scheduler
+ */
+#ifdef KPROF
+unsigned short kcount[20000];
+#endif
+
+/*
+ * We handle regular calls to the dh and dz silo input processors
+ * without using timeouts to save a little time.
+ */
+int    rintvl = 0;             /* every 1/60'th of sec check receivers */
+int    rcnt;
+
+clock(pc, ps)
+caddr_t pc;
+{
+       register struct callo *p1, *p2;
+       register struct proc *pp;
+       register int s;
+       int a, cpstate, i;
+
+       /*
+        * reprime clock
+        */
+       clkreld();
+
+       /*
+        * callouts
+        * 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:
+
+       /*
+        * In order to not take input character interrupts to use
+        * the input silo on DZ's we have to guarantee to echo
+        * characters regularly.  This means that we have to
+        * call the timer routines predictably.  Since blocking
+        * in these routines is at spl5(), we have to make spl5()
+        * really spl6() blocking off the clock to put this code
+        * here.  Note also that it is critical that we run spl5()
+        * (i.e. really spl6()) in the receiver interrupt routines
+        * so we can't enter them recursively and transpose characters.
+        */
+       if (rcnt >= rintvl) {
+#if NDH11 > 0
+               dhtimer();
+#endif
+#if NDZ11 > 0
+               dztimer();
+#endif
+               rcnt = 0;
+       } else
+               rcnt++;
+       if (!noproc) {
+               s = u.u_procp->p_rssize;
+               u.u_vm.vm_idsrss += s;
+               if (u.u_procp->p_textp) {
+                       register int xrss = u.u_procp->p_textp->x_rssize;
+
+                       s += xrss;
+                       u.u_vm.vm_ixrss += xrss;
+               }
+               if (s > u.u_vm.vm_maxrss)
+                       u.u_vm.vm_maxrss = s;
+               if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) {
+                       psignal(u.u_procp, SIGXCPU);
+                       if (u.u_limit[LIM_CPU] < INFINITY - 5)
+                               u.u_limit[LIM_CPU] += 5;
+               }
+       }
+       if (USERMODE(ps)) {
+               u.u_vm.vm_utime++;
+               if(u.u_procp->p_nice > NZERO)
+                       cpstate = CP_NICE;
+               else
+                       cpstate = CP_USER;
+       } else {
+               cpstate = CP_SYS;
+               if (noproc)
+                       cpstate = CP_IDLE;
+               else
+                       u.u_vm.vm_stime++;
+       }
+       cp_time[cpstate]++;
+       for (i = 0; i < DK_NDRIVE; i++)
+               if (dk_busy&(1<<i))
+                       dk_time[i]++;
+       if (!noproc) {
+               pp = u.u_procp;
+               pp->p_cpticks++;
+               if(++pp->p_cpu == 0)
+                       pp->p_cpu--;
+               if(pp->p_cpu % 16 == 0) {
+                       (void) setpri(pp);
+                       if (pp->p_pri >= PUSER)
+                               pp->p_pri = pp->p_usrpri;
+               }
+       }
+       ++lbolt;
+       if (lbolt % (HZ/4) == 0) {
+               vmpago();
+               runrun++;
+       }
+       if (lbolt >= HZ) {
+               extern int hangcnt;
+
+               if (BASEPRI(ps))
+                       return;
+               lbolt -= HZ;
+               ++time;
+               (void) spl1();
+               /*
+                * machdep.c:unhang uses hangcnt to make sure uba
+                * doesn't forget to interrupt (this has been observed).
+                * This prevents an accumulation of < 5 second uba failures
+                * from summing to a uba reset.
+                */
+               if (hangcnt)
+                       hangcnt--;
+               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)
+                                       if (pp->p_flag & STIMO) {
+                                               s = spl6();
+                                               switch (pp->p_stat) {
+
+                                               case SSLEEP:
+                                                       setrun(pp);
+                                                       break;
+
+                                               case SSTOP:
+                                                       unsleep(pp);
+                                                       break;
+                                               }
+                                               pp->p_flag &= ~STIMO;
+                                               splx(s);
+                                       } else
+                                               psignal(pp, SIGALRM);
+                       if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP)
+                               if (pp->p_slptime != 127)
+                                       pp->p_slptime++;
+                       if (pp->p_flag&SLOAD)
+                               pp->p_pctcpu = ccpu * pp->p_pctcpu +
+                                   (1.0 - ccpu) * (pp->p_cpticks/(float)HZ);
+                       pp->p_cpticks = 0;
+                       a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
+                       if(a < 0)
+                               a = 0;
+                       if(a > 255)
+                               a = 255;
+                       pp->p_cpu = a;
+                       (void) setpri(pp);
+                       s = spl6();
+                       if(pp->p_pri >= PUSER) {
+                               if ((pp != u.u_procp || noproc) &&
+                                   pp->p_stat == SRUN &&
+                                   (pp->p_flag & SLOAD) &&
+                                   pp->p_pri != pp->p_usrpri) {
+                                       remrq(pp);
+                                       pp->p_pri = pp->p_usrpri;
+                                       setrq(pp);
+                               } else
+                                       pp->p_pri = pp->p_usrpri;
+                       }
+                       splx(s);
+               }
+               vmmeter();
+               if(runin!=0) {
+                       runin = 0;
+                       wakeup((caddr_t)&runin);
+               }
+               /*
+                * If there are pages that have been cleaned, 
+                * jolt the pageout daemon to process them.
+                * We do this here so that these pages will be
+                * freed if there is an abundance of memory and the
+                * daemon would not be awakened otherwise.
+                */
+               if (bclnlist != NULL)
+                       wakeup((caddr_t)&proc[2]);
+               if (USERMODE(ps)) {
+                       pp = u.u_procp;
+#ifdef ERNIE
+                       if (pp->p_uid)
+                               if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ)
+                                       pp->p_nice = NZERO+4;
+                       (void) setpri(pp);
+                       pp->p_pri = pp->p_usrpri;
+#endif
+               }
+       }
+       if (!BASEPRI(ps))
+               unhang();
+       if (USERMODE(ps)) {
+               /*
+                * We do this last since it
+                * may block on a page fault in user space.
+                */
+               if (u.u_prof.pr_scale)
+                       addupc(pc, &u.u_prof, 1);
+       }
+#ifdef KPROF
+       else if (!noproc) {
+               register int indx = ((int)pc & 0x7fffffff) / 4;
+
+               if (indx >= 0 && indx < 20000)
+                       if (++kcount[indx] == 0)
+                               --kcount[indx];
+       }
+#endif
+}
+
+/*
+ * 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/sys/sys/fio.c b/usr/src/sys/sys/fio.c
new file mode 100644 (file)
index 0000000..ada4fd7
--- /dev/null
@@ -0,0 +1,273 @@
+/*     fio.c   4.1     11/9/80 */
+
+#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.
+ * Call device handler on last close.
+ */
+closef(fp)
+register struct file *fp;
+{
+       register struct inode *ip;
+       int flag, mode;
+       dev_t dev;
+       register int (*cfunc)();
+       struct chan *cp;
+
+       if(fp == NULL)
+               return;
+       if (fp->f_count > 1) {
+               fp->f_count--;
+               return;
+       }
+       ip = fp->f_inode;
+       flag = fp->f_flag;
+       cp = fp->f_un.f_chan;
+       dev = (dev_t)ip->i_un.i_rdev;
+       mode = ip->i_mode;
+
+       plock(ip);
+       fp->f_count = 0;
+       if(flag & FPIPE) {
+               ip->i_mode &= ~(IREAD|IWRITE);
+               wakeup((caddr_t)ip+1);
+               wakeup((caddr_t)ip+2);
+       }
+       iput(ip);
+
+       switch(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 (flag & FMP)
+               goto call;
+
+       for(fp=file; fp < &file[NFILE]; fp++)
+               if (fp->f_count && (ip=fp->f_inode)->i_un.i_rdev==dev &&
+                   (ip->i_mode&IFMT) == (mode&IFMT))
+                       return;
+
+call:
+       (*cfunc)(dev, flag, cp);
+}
+
+/*
+ * 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);
+}
+
+struct file *lastf = &file[0];
+/*
+ * 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 = lastf; fp < &file[NFILE]; fp++)
+               if(fp->f_count == 0)
+                       goto slot;
+       for(fp = &file[0]; fp < lastf; fp++)
+               if(fp->f_count == 0)
+                       goto slot;
+       printf("no file\n");
+       u.u_error = ENFILE;
+       return(NULL);
+slot:
+       u.u_ofile[i] = fp;
+       fp->f_count++;
+       fp->f_un.f_offset = 0;
+       lastf = fp + 1;
+       return(fp);
+}
diff --git a/usr/src/sys/sys/iget.c b/usr/src/sys/sys/iget.c
new file mode 100644 (file)
index 0000000..d85cd4d
--- /dev/null
@@ -0,0 +1,413 @@
+/*     iget.c  4.1     11/9/80 */
+
+#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"
+#include "../h/inline.h"
+
+#define        INOHSZ  63
+#define        INOHASH(dev,ino)        (((dev)+(ino))%INOHSZ)
+short  inohash[INOHSZ];
+short  ifreel;
+
+/*
+ * Initialize hash links for inodes
+ * and build inode free list.
+ */
+ihinit()
+{
+       register int i;
+
+       ifreel = 0;
+       for (i = 0; i < NINODE - 1; i++)
+               inode[i].i_hlink = i+1;
+       inode[NINODE - 1].i_hlink = -1;
+       for (i = 0; i < INOHSZ; i++)
+               inohash[i] = -1;
+}
+
+/*
+ * Find an inode if it is incore.
+ * This is the equivalent, for inodes,
+ * of ``incore'' in bio.c or ``pfind'' in subr.c.
+ */
+struct inode *
+ifind(dev, ino)
+dev_t dev;
+ino_t ino;
+{
+       register struct inode *ip;
+
+       for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1];
+           ip = &inode[ip->i_hlink])
+               if (ino==ip->i_number && dev==ip->i_dev)
+                       return (ip);
+       return ((struct inode *)0);
+}
+
+/*
+ * 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 buf *bp;
+       register struct dinode *dp;
+       register int slot;
+
+loop:
+       slot = INOHASH(dev, ino);
+       ip = &inode[inohash[slot]];
+       while (ip != &inode[-1]) {
+               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);
+               }
+               ip = &inode[ip->i_hlink];
+       }
+       if(ifreel < 0) {
+               printf("Inode table overflow\n");
+               u.u_error = ENFILE;
+               return(NULL);
+       }
+       ip = &inode[ifreel];
+       ifreel = ip->i_hlink;
+       ip->i_hlink = inohash[slot];
+       inohash[slot] = ip - inode;
+       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, *p2;
+       register 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;
+{
+       register int i, x;
+       register struct inode *jp;
+
+       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, 0);
+               prele(ip);
+               i = INOHASH(ip->i_dev, ip->i_number);
+               x = ip - inode;
+               if (inohash[i] == x) {
+                       inohash[i] = ip->i_hlink;
+               } else {
+                       for (jp = &inode[inohash[i]]; jp != &inode[-1];
+                           jp = &inode[jp->i_hlink])
+                               if (jp->i_hlink == x) {
+                                       jp->i_hlink = ip->i_hlink;
+                                       goto done;
+                               }
+                       panic("iput");
+               }
+done:
+               ip->i_hlink = ifreel;
+               ifreel = x;
+               ip->i_flag = 0;
+               ip->i_number = 0;
+       } else
+               prele(ip);
+       ip->i_count--;
+}
+
+/*
+ * Check accessed and update flags on
+ * an inode structure.
+ * If any is on, update the inode
+ * with the current time.
+ * If waitfor is given, then must insure
+ * i/o order so wait for write to complete.
+ */
+iupdat(ip, ta, tm, waitfor)
+register struct inode *ip;
+time_t *ta, *tm;
+int waitfor;
+{
+       register struct buf *bp;
+       struct dinode *dp;
+       register char *p1, *p2;
+       register 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);
+               if (waitfor)
+                       bwrite(bp);
+               else
+                       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;
+       struct inode itmp;
+
+       if (ip->i_vfdcnt)
+               panic("itrunc");
+       i = ip->i_mode & IFMT;
+       if (i!=IFREG && i!=IFDIR)
+               return;
+
+       /*
+        * Clean inode on disk before freeing blocks
+        * to insure no duplicates if system crashes.
+        */
+       itmp = *ip;
+       itmp.i_size = 0;
+       for (i = 0; i < NADDR; i++)
+               itmp.i_un.i_addr[i] = 0;
+       itmp.i_flag |= ICHG|IUPD;
+       iupdat(&itmp, &time, &time, 1);
+       ip->i_flag &= ~(IUPD|IACC|ICHG);
+
+       /*
+        * Now return blocks to free list... if machine
+        * crashes, they will be harmless MISSING blocks.
+        */
+       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;
+       /*
+        * Inode was written and flags updated above.
+        * No need to modify flags here.
+        */
+}
+
+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;
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       iupdat(ip, &time, &time, 1);
+
+       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/sys/sys/malloc.c b/usr/src/sys/sys/malloc.c
new file mode 100644 (file)
index 0000000..3cda96a
--- /dev/null
@@ -0,0 +1,112 @@
+/*     malloc.c        4.1     11/9/80 */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/map.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/mtpr.h"
+#include "../h/text.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 swap map unit is 512 bytes.
+ * Algorithm is first-fit.
+ */
+malloc(mp, size)
+struct map *mp;
+{
+       register int a;
+       register struct map *bp;
+       swblk_t first, rest;
+
+       if (size <= 0 || mp == swapmap && size > DMMAX)
+               panic("malloc");
+       for (bp=mp; bp->m_size; bp++) {
+               if (bp->m_size >= size) {
+                       if (mp == swapmap &&
+                           (first = DMMAX - bp->m_addr%DMMAX) < bp->m_size) {
+                               if (bp->m_size - first < size)
+                                       continue;
+                               a = bp->m_addr + first;
+                               rest = bp->m_size - first - size;
+                               bp->m_size = first;
+                               if (rest)
+                                       mfree(swapmap, rest, a+size);
+                               return (a);
+                       }
+                       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);
+                       }
+                       if (mp == swapmap && a % CLSIZE)
+                               panic("malloc swapmap");
+                       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 int size, a;
+{
+       register struct map *bp;
+       register int t;
+
+       if (a <= 0)
+               panic("mfree addr");
+       if (size <= 0)
+               panic("mfree size");
+       bp = mp;
+       for (; bp->m_addr<=a && bp->m_size!=0; bp++)
+               continue;
+       if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size > a)
+               panic("mfree begov");
+       if (a+size > bp->m_addr && bp->m_size)
+               panic("mfree endov");
+       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);
+               }
+       }
+       if ((mp == kernelmap) && kmapwnt) {
+               kmapwnt = 0;
+               wakeup((caddr_t)kernelmap);
+       }
+}
diff --git a/usr/src/sys/sys/partab.c b/usr/src/sys/sys/partab.c
new file mode 100644 (file)
index 0000000..560909a
--- /dev/null
@@ -0,0 +1,42 @@
+/*     partab.c        4.1     11/9/80 */
+
+/*
+ */
+
+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,
+
+       /* Addition for the benefit of ttwrite */
+
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007,
+       0007,0007,0007,0007,0007,0007,0007,0007
+};
diff --git a/usr/src/sys/sys/prim.c b/usr/src/sys/sys/prim.c
new file mode 100644 (file)
index 0000000..6711daa
--- /dev/null
@@ -0,0 +1,403 @@
+/*     prim.c  4.1     11/9/80 */
+
+#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];
+int    cbad;
+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);
+}
+
+/*
+ * copy clist to buffer.
+ * return number of bytes moved.
+ */
+q_to_b(q, cp, cc)
+register struct clist *q;
+register char *cp;
+{
+       register struct cblock *bp;
+       register int s;
+       char *acp;
+
+       if (cc <= 0)
+               return(0);
+       s = spl6();
+       if (q->c_cc <= 0) {
+               q->c_cc = 0;
+               q->c_cf = q->c_cl = NULL;
+               return(0);
+       }
+       acp = cp;
+       cc++;
+
+       while (--cc) {
+               *cp++ = *q->c_cf++;
+               if (--q->c_cc <= 0) {
+                       bp = (struct cblock *)(q->c_cf-1);
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       q->c_cf = q->c_cl = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       break;
+               }
+               if (((int)q->c_cf & CROUND) == 0) {
+                       bp = (struct cblock *)(q->c_cf);
+                       bp--;
+                       q->c_cf = bp->c_next->c_info;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               }
+       }
+       splx(s);
+       return(cp-acp);
+}
+
+/*
+ * Return count of contiguous characters
+ * in clist starting at q->c_cf.
+ * Stop counting if flag&character is non-null.
+ */
+ndqb(q, flag)
+register struct clist *q;
+{
+register cc;
+int s;
+
+       s = spl6();
+       if (q->c_cc <= 0) {
+               cc = -q->c_cc;
+               goto out;
+       }
+       cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
+       cc -= (int)q->c_cf;
+       if (q->c_cc < cc)
+               cc = q->c_cc;
+       if (flag) {
+               register char *p, *end;
+
+               p = q->c_cf;
+               end = p;
+               end += cc;
+               while (p < end) {
+                       if (*p & flag) {
+                               cc = (int)p - (int)q->c_cf;
+                               break;
+                       }
+                       p++;
+               }
+       }
+out:
+       splx(s);
+       return(cc);
+}
+
+/*
+ * Update clist to show that cc characters
+ * were removed.  It is assumed that cc < CBSIZE.
+ */
+ndflush(q, cc)
+register struct clist *q;
+register cc;
+{
+register s;
+
+       if (cc == 0)
+               return;
+       s = spl6();
+       if (q->c_cc < 0) {
+               if (q->c_cf != NULL) {
+                       q->c_cc += cc;
+                       q->c_cf += cc;
+                       goto out;
+               }
+               q->c_cc = 0;
+               goto out;
+       }
+       if (q->c_cc == 0) {
+               goto out;
+       }
+       if (cc > CBSIZE || cc <= 0) {
+               cbad++;
+               goto out;
+       }
+       q->c_cc -= cc;
+       q->c_cf += cc;
+       if (((int)q->c_cf & CROUND) == 0) {
+               register struct cblock *bp;
+
+               bp = (struct cblock *)(q->c_cf) -1;
+               if (bp->c_next) {
+                       q->c_cf = bp->c_next->c_info;
+               } else {
+                       q->c_cf = q->c_cl = NULL;
+               }
+               bp->c_next = cfreelist;
+               cfreelist = bp;
+       } else
+       if (q->c_cc == 0) {
+               register struct cblock *bp;
+               q->c_cf = (char *)((int)q->c_cf & ~CROUND);
+               bp = (struct cblock *)(q->c_cf);
+               bp->c_next = cfreelist;
+               cfreelist = bp;
+               q->c_cf = q->c_cl = NULL;
+       }
+out:
+       splx(s);
+}
+
+/*
+ * Put character c in queue p.
+ */
+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);
+}
+
+/*
+ * copy buffer to clist.
+ * return number of bytes not transfered.
+ */
+b_to_q(cp, cc, q)
+register char *cp;
+struct clist *q;
+register int cc;
+{
+       register char *cq;
+       register struct cblock *bp;
+       register s, acc;
+
+       if (cc <= 0)
+               return(0);
+       acc = cc;
+       s = spl6();
+       if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
+               if ((bp = cfreelist) == NULL) 
+                       goto out;
+               cfreelist = bp->c_next;
+               bp->c_next = NULL;
+               q->c_cf = cq = bp->c_info;
+       }
+
+       while (cc) {
+               if (((int)cq & CROUND) == 0) {
+                       bp = (struct cblock *) cq - 1;
+                       if ((bp->c_next = cfreelist) == NULL) 
+                               goto out;
+                       bp = bp->c_next;
+                       cfreelist = bp->c_next;
+                       bp->c_next = NULL;
+                       cq = bp->c_info;
+               }
+               *cq++ = *cp++;
+               cc--;
+       }
+out:
+       q->c_cl = cq;
+       q->c_cc += acc-cc;
+       splx(s);
+       return(cc);
+}
+
+/*
+ * Given a non-NULL pointter into the list (like c_cf which
+ * always points to a real character if non-NULL) return the pointer
+ * to the next character in the list or return NULL if no more chars.
+ *
+ * Callers must not allow getc's to happen between nextc's so that the
+ * pointer becomes invalid.  Note that interrupts are NOT masked.
+ */
+char *
+nextc(p, cp)
+register struct clist *p;
+register char *cp;
+{
+
+       if (p->c_cc && ++cp != p->c_cl) {
+               if (((int)cp & CROUND) == 0)
+                       return (((struct cblock *)cp)[-1].c_next->c_info);
+               return (cp);
+       }
+       return (0);
+}
+
+/*
+ * Remove the last character in the list and return it.
+ */
+unputc(p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register int c, s;
+       struct cblock *obp;
+
+       s = spl6();
+       if (p->c_cc <= 0)
+               c = -1;
+       else {
+               c = *--p->c_cl;
+               if (--p->c_cc <= 0) {
+                       bp = (struct cblock *)p->c_cl;
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       p->c_cl = p->c_cf = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+               } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
+                       p->c_cl = (char *)((int)p->c_cl & ~CROUND);
+                       bp = (struct cblock *)p->c_cf;
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       while (bp->c_next != (struct cblock *)p->c_cl)
+                               bp = bp->c_next;
+                       obp = bp;
+                       p->c_cl = (char *)(bp + 1);
+                       bp = bp->c_next;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       obp->c_next = NULL;
+               }
+       }
+       splx(s);
+       return (c);
+}
+
+/*
+ * Put the chars in the from que
+ * on the end of the to que.
+ *
+ * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
+ */
+catq(from, to)
+struct clist *from, *to;
+{
+       register c;
+
+       while ((c = getc(from)) >= 0)
+               (void) putc(c, to);
+}
+
+/*
+ * 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);
+       }
+       (void) putc(c, p);
+       (void) putc(c>>8, p);
+       splx(s);
+       return(0);
+}
diff --git a/usr/src/sys/sys/subr.c b/usr/src/sys/sys/subr.c
new file mode 100644 (file)
index 0000000..ee3537b
--- /dev/null
@@ -0,0 +1,238 @@
+/*     subr.c  4.1     11/9/80 */
+
+#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"
+#include "../h/proc.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 = dbtofsb(bp->b_blkno);
+                       if ((ip->i_mode&IFMT) == IFDIR)
+                               /*
+                                * Write directory blocks synchronously
+                                * so they never appear with garbage in
+                                * them on the disk.
+                                */
+                               bwrite(bp);
+                       else
+                               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 first indirect block
+        */
+       nb = ip->i_un.i_addr[NADDR-j];
+       if(nb == 0) {
+               if(rwflg==B_READ || (bp = alloc(dev))==NULL)
+                       return((daddr_t)-1);
+               nb = dbtofsb(bp->b_blkno);
+               /*
+                * Write synchronously so that indirect blocks
+                * never point at garbage.
+                */
+               bwrite(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 = dbtofsb(nbp->b_blkno);
+                       if (j < 3 || (ip->i_mode&IFMT) == IFDIR)
+                               /*
+                                * Write synchronously so indirect blocks
+                                * never point at garbage and blocks
+                                * in directories never contain garbage.
+                                */
+                               bwrite(nbp);
+                       else
+                               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()
+{
+
+}
+
+imin(a, b)
+{
+
+       return (a < b ? a : b);
+}
+
+imax(a, b)
+{
+
+       return (a > b ? a : b);
+}
+
+struct proc *
+pfind(pid)
+       int pid;
+{
+       register struct proc *p;
+
+       for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash])
+               if (p->p_pid == pid)
+                       return (p);
+       return ((struct proc *)0);
+}
diff --git a/usr/src/sys/sys/swtch.c b/usr/src/sys/sys/swtch.c
new file mode 100644 (file)
index 0000000..76d2607
--- /dev/null
@@ -0,0 +1,127 @@
+/*     swtch.c 4.1     11/9/80 */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/file.h"
+#include "../h/inode.h"
+#include "../h/vm.h"
+#include "../h/pte.h"
+
+/*
+ * PORTABLE DEFINITIONS OF setrq(), remrq() and swtch().
+ * These are primitives in locore.s on the VAX.
+ */
+
+#ifndef FASTVAX
+/*
+ * 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");
+                       asm("halt");
+                       goto out;
+               }
+       p->p_link = runq;
+       runq = p;
+out:
+       splx(s);
+}
+
+/*
+ * Remove runnable job from run queue.
+ * This is done when a runnable job is swapped
+ * out so that it won't be selected in swtch().
+ * It will be reinserted in the runq with setrq
+ * when it is swapped back in.
+ */
+remrq(p)
+       register struct proc *p;
+{
+       register struct proc *q;
+       int s;
+
+       s = spl6();
+       if (p == runq)
+               runq = p->p_link;
+       else {
+               for (q = runq; q; q = q->p_link)
+                       if (q->p_link == p) {
+                               q->p_link = p->p_link;
+                               goto done;
+                       }
+               panic("remque");
+done:
+               ;
+       }
+       splx(s);
+}
+
+/*
+ * 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;
+
+       noproc = 1;
+loop:
+       (void) 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_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;
+       (void) spl0();
+       cnt.v_swtch++;
+       noproc = 0;
+       if (p != u.u_procp)
+               resume(pcbb(p));
+}
+#endif
diff --git a/usr/src/sys/sys/sys.c b/usr/src/sys/sys/sys.c
new file mode 100644 (file)
index 0000000..6306db0
--- /dev/null
@@ -0,0 +1,45 @@
+/*     sys.c   4.1     11/9/80 */
+
+/*
+ *     indirect driver for controlling tty.
+ */
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/conf.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/tty.h"
+#include "../h/proc.h"
+
+/*ARGSUSED*/
+syopen(dev, flag)
+{
+
+       if(u.u_ttyp == NULL) {
+               u.u_error = ENXIO;
+               return;
+       }
+       (*cdevsw[major(u.u_ttyd)].d_open)(u.u_ttyd, flag);
+}
+
+/*ARGSUSED*/
+syread(dev)
+{
+
+       (*cdevsw[major(u.u_ttyd)].d_read)(u.u_ttyd);
+}
+
+/*ARGSUSED*/
+sywrite(dev)
+{
+
+       (*cdevsw[major(u.u_ttyd)].d_write)(u.u_ttyd);
+}
+
+/*ARGSUSED*/
+syioctl(dev, cmd, addr, flag)
+caddr_t addr;
+{
+
+       (*cdevsw[major(u.u_ttyd)].d_ioctl)(u.u_ttyd, cmd, addr, flag);
+}
diff --git a/usr/src/sys/sys/sys3.c b/usr/src/sys/sys/sys3.c
new file mode 100644 (file)
index 0000000..1ff6e20
--- /dev/null
@@ -0,0 +1,269 @@
+/*     sys3.c  4.1     11/9/80 */
+
+#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"
+#include "../h/inline.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, 0);
+       /*
+        * 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;
+               }
+               if (u.u_vrpages[i]) {
+                       u.u_error = ETXTBSY;
+                       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;
+       fp->s_nbehind = 0;
+       fp->s_lasti = 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;
+               }
+       mpurge(mp - &mount[0]);
+       (*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;
+
+#ifdef UCB
+       if (!suser())
+               return(NODEV);
+#endif
+       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/sys/sys/sys4.c b/usr/src/sys/sys/sys4.c
new file mode 100644 (file)
index 0000000..e3dd4cb
--- /dev/null
@@ -0,0 +1,624 @@
+/*     sys4.c  4.1     11/9/80 */
+
+#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"
+#include "../h/times.h"
+#include "../h/reboot.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;
+       if (clkwrap())
+               clkset();
+}
+
+/*
+ * 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;
+       (void) spl7();
+       t.time = time;
+       ms = lbolt;
+       (void) 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;
+       if (clkwrap())
+               clkset();
+}
+
+/*
+ * Set the time
+ */
+stime()
+{
+       register struct a {
+               time_t  time;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if(suser()) {
+               bootime += uap->time - time;
+               time = uap->time;
+               clkset();
+       }
+}
+
+setuid()
+{
+       register uid;
+       register struct a {
+               int     uid;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       uid = uap->uid;
+       if(u.u_ruid == uid || u.u_uid == 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 || u.u_gid == 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;
+       (void) setpri(u.u_procp);
+       /* IF RUNNING MAY HAVE WRONG p->p_pri, BUT WILL FIX ITSELF QUICKLY */
+}
+
+/*
+ * 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()
+{
+       if (suser())
+               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);
+#ifdef ERNIE
+       if ((ip->i_mode & ISUID) && ip->i_uid == 0)
+               printf("SETUID ROOT: number %d dev %d\n", ip->i_number, ip->i_dev);
+#endif
+       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;
+#ifdef ERNIE
+       ip->i_mode &= ~(ISUID|ISGID);
+#endif
+       iput(ip);
+}
+
+ssig()
+{
+       register int (*f)();
+       struct a {
+               int     signo;
+               int     (*fun)();
+       } *uap;
+       register struct proc *p = u.u_procp;
+       register a;
+       long sigmask;
+
+       uap = (struct a *)u.u_ap;
+       a = uap->signo & SIGNUMMASK;
+       f = uap->fun;
+       if(a<=0 || a>=NSIG || a==SIGKILL || a==SIGSTOP ||
+           a==SIGCONT && (f == SIG_IGN || f == SIG_HOLD)) {
+               u.u_error = EINVAL;
+               return;
+       }
+       if ((uap->signo &~ SIGNUMMASK) || (f != SIG_DFL && f != SIG_IGN &&
+           SIGISDEFER(f)))
+               u.u_procp->p_flag |= SNUSIG;
+       /* 
+        * Don't clobber registers if we are to simulate
+        * a ret+rti.
+        */
+       if ((uap->signo&SIGDORTI) == 0)
+               u.u_r.r_val1 = (int)u.u_signal[a];
+       /*
+        * Change setting atomically.
+        */
+       (void) spl6();
+       sigmask = 1L << (a-1);
+       if (u.u_signal[a] == SIG_IGN)
+               p->p_sig &= ~sigmask;           /* never to be seen again */
+       u.u_signal[a] = f;
+       if (f != SIG_DFL && f != SIG_IGN && f != SIG_HOLD)
+               f = SIG_CATCH;
+       if ((int)f & 1)
+               p->p_siga0 |= sigmask;
+       else
+               p->p_siga0 &= ~sigmask;
+       if ((int)f & 2)
+               p->p_siga1 |= sigmask;
+       else
+               p->p_siga1 &= ~sigmask;
+       (void) spl0();
+       /*
+        * Now handle options.
+        */
+       if (uap->signo & SIGDOPAUSE) {
+               /*
+                * Simulate a PDP11 style wait instrution which
+                * atomically lowers priority, enables interrupts
+                * and hangs.
+                */
+               pause();
+               /*NOTREACHED*/
+       }
+       if (uap->signo & SIGDORTI)
+               u.u_eosys = SIMULATERTI;
+}
+
+kill()
+{
+       register struct proc *p;
+       register a, sig;
+       register struct a {
+               int     pid;
+               int     signo;
+       } *uap;
+       int f, priv;
+
+       uap = (struct a *)u.u_ap;
+       f = 0;
+       a = uap->pid;
+       priv = 0;
+       sig = uap->signo;
+       if (sig < 0)
+               /*
+                * A negative signal means send to process group.
+                */
+               uap->signo = -uap->signo;
+       if (uap->signo == 0 || uap->signo > NSIG) {
+               u.u_error = EINVAL;
+               return;
+       }
+       if (a > 0 && sig > 0) {
+               p = pfind(a);
+               if (p == 0 || u.u_uid && u.u_uid != p->p_uid) {
+                       u.u_error = ESRCH;
+                       return;
+               }
+               psignal(p, uap->signo);
+               return;
+       }
+       if (a==-1 && u.u_uid==0) {
+               priv++;
+               a = 0;
+               sig = -1;               /* like sending to pgrp */
+       } else if(a==0) {
+               /*
+                * Zero process id means send to my process group.
+                */
+               sig = -1;
+               a = u.u_procp->p_pgrp;
+               if (a == 0) {
+                       u.u_error = EINVAL;
+                       return;
+               }
+       }
+       for(p = &proc[0]; p < &proc[NPROC]; p++) {
+               if(p->p_stat == NULL)
+                       continue;
+               if(sig > 0) {
+                       if (p->p_pid != a)
+                               continue;
+               } else if (p->p_pgrp!=a && priv==0 || p<=&proc[2])
+                       continue;
+               if(u.u_uid != 0 && u.u_uid != p->p_uid &&
+                   (uap->signo != SIGCONT || !inferior(p)))
+                       continue;
+               f++;
+               psignal(p, uap->signo);
+       }
+       if(f == 0)
+               u.u_error = ESRCH;
+}
+
+times()
+{
+       register struct a {
+               time_t  (*times)[4];
+       } *uap;
+       struct tms tms;
+
+       tms.tms_utime = u.u_vm.vm_utime;
+       tms.tms_stime = u.u_vm.vm_stime;
+       tms.tms_cutime = u.u_cvm.vm_utime;
+       tms.tms_cstime = u.u_cvm.vm_stime;
+       uap = (struct a *)u.u_ap;
+       if (copyout((caddr_t)&tms, (caddr_t)uap->times, sizeof(struct tms)) < 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;
+       } else {
+               ip->i_flag |= IACC|IUPD|ICHG;
+               iupdat(ip, &tv[0], &tv[1], 0);
+       }
+       iput(ip);
+}
+
+/*
+ * Setpgrp on specified process and its descendants.
+ * Pid of zero implies current process.
+ * Pgrp -1 is getpgrp system call returning
+ * current process group.
+ */
+setpgrp()
+{
+       register struct proc *top;
+       register struct a {
+               int     pid;
+               int     pgrp;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (uap->pid == 0)
+               top = u.u_procp;
+       else {
+               top = pfind(uap->pid);
+               if (top == 0) {
+                       u.u_error = ESRCH;
+                       return;
+               }
+       }
+       if (uap->pgrp <= 0) {
+               u.u_r.r_val1 = top->p_pgrp;
+               return;
+       }
+#ifdef notdef
+       u.u_r.r_val1 = spgrp(top, uap->pgrp);
+       if (u.u_r.r_val1 == 0)
+               u.u_error = EPERM;
+#else
+       if (top->p_uid != u.u_uid && u.u_uid && !inferior(top))
+               u.u_error = EPERM;
+       else
+               top->p_pgrp = uap->pgrp;
+#endif
+}
+
+spgrp(top, npgrp)
+register struct proc *top;
+{
+       register struct proc *pp, *p;
+       int f = 0;
+
+       for (p = top; npgrp == -1 || u.u_uid == p->p_uid ||
+           !u.u_uid || inferior(p); p = pp) {
+               if (npgrp == -1) {
+#define        bit(a)  (1<<(a-1))
+                       p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU));
+                       p->p_flag |= SDETACH;
+               } else
+                       p->p_pgrp = npgrp;
+               f++;
+               /*
+                * Search for children.
+                */
+               for (pp = &proc[0]; pp < &proc[NPROC]; pp++)
+                       if (pp->p_pptr == p)
+                               goto cont;
+               /*
+                * Search for siblings.
+                */
+               for (; p != top; p = p->p_pptr)
+                       for (pp = p + 1; pp < &proc[NPROC]; pp++)
+                               if (pp->p_pptr == p->p_pptr)
+                                       goto cont;
+               break;
+       cont:
+               ;
+       }
+       return (f);
+}
+
+/*
+ * Is p an inferior of the current process?
+ */
+inferior(p)
+register struct proc *p;
+{
+
+       for (; p != u.u_procp; p = p->p_pptr)
+               if (p <= &proc[2])
+                       return (0);
+       return (1);
+}
+
+reboot()
+{
+       register struct a {
+               int     opt;
+       };
+
+       if (suser())
+               boot(RB_BOOT, ((struct a *)u.u_ap)->opt);
+}
diff --git a/usr/src/sys/sys/sysent.c b/usr/src/sys/sys/sysent.c
new file mode 100644 (file)
index 0000000..56a9c49
--- /dev/null
@@ -0,0 +1,139 @@
+/*     sysent.c        4.1     11/9/80 */
+
+/*
+ * 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    reboot();
+int    rexit();
+int    saccess();
+int    sbreak();
+int    seek();
+int    setgid();
+int    setpgrp();
+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();
+
+#include "../h/vmsysent.h"
+
+struct sysent sysent[128] =
+{
+       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 */
+       2, 0, setpgrp,                  /* 39 = setpgrp */
+       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 */
+       1, 0, reboot,                   /* 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 */
+       0, 0, nosys,                    /* 62 = reserved to local sites */
+       0, 0, nosys,                    /* 63 = used internally */
+#include "vmsysent.c"
+};
diff --git a/usr/src/sys/sys/text.c b/usr/src/sys/sys/text.c
new file mode 100644 (file)
index 0000000..e805df5
--- /dev/null
@@ -0,0 +1,302 @@
+/*     text.c  4.1     11/9/80 */
+
+#include "../h/param.h"
+#include "../h/systm.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/pte.h"
+#include "../h/mtpr.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+/*
+ * 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);
+       ip = xp->x_iptr;
+       if(--xp->x_count==0 && (ip->i_mode&ISVTX)==0) {
+               xunlink(u.u_procp);
+               xp->x_rssize -= vmemfree(tptopte(u.u_procp, 0), u.u_tsize);
+               if (xp->x_rssize != 0)
+                       panic("xfree rssize");
+               ip->i_flag &= ~ITEXT;
+               if (ip->i_flag&ILOCK)
+                       ip->i_count--;
+               else
+                       iput(ip);
+               while (xp->x_poip)
+                       sleep((caddr_t)&xp->x_poip, PSWP+1);
+               vsxfree(xp, xp->x_size);
+               xp->x_flag &= ~XLOCK;
+               xp->x_iptr = NULL;
+       } else {
+               xp->x_flag &= ~XLOCK;
+               xccdec(xp, u.u_procp);
+       }
+       u.u_procp->p_textp = NULL;
+}
+
+/*
+ * 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, pagi)
+register struct inode *ip;
+{
+       register struct text *xp;
+       register size_t ts;
+       register struct text *xp1;
+
+       if(u.u_exdata.ux_tsize == 0)
+               return;
+again:
+       xp1 = NULL;
+       for (xp = &text[0]; xp < &text[NTEXT]; xp++) {
+               if(xp->x_iptr == NULL) {
+                       if(xp1 == NULL)
+                               xp1 = xp;
+                       continue;
+               }
+               if ((xp->x_count > 0 || (xp->x_iptr->i_mode&ISVTX)) && xp->x_iptr == ip) {
+                       if (xp->x_flag&XLOCK) {
+                               xwait(xp);
+                               goto again;
+                       }
+                       xlock(xp);
+                       xp->x_count++;
+                       u.u_procp->p_textp = xp;
+                       xlink(u.u_procp);
+                       xunlock(xp);
+                       return;
+               }
+       }
+       if((xp=xp1) == NULL) {
+               printf("out of text");
+               psignal(u.u_procp, SIGKILL);
+               return;
+       }
+       xp->x_flag = XLOAD|XLOCK;
+       if (pagi)
+               xp->x_flag |= XPAGI;
+       ts = clrnd(btoc(u.u_exdata.ux_tsize));
+       xp->x_size = ts;
+       if (vsxalloc(xp) == NULL) {
+               swkill(u.u_procp, "xalloc");
+               return;
+       }
+       xp->x_count = 1;
+       xp->x_ccount = 0;
+       xp->x_rssize = 0;
+       xp->x_iptr = ip;
+       ip->i_flag |= ITEXT;
+       ip->i_count++;
+       u.u_procp->p_textp = xp;
+       xlink(u.u_procp);
+       if (pagi == 0) {
+               u.u_count = u.u_exdata.ux_tsize;
+               u.u_offset = sizeof(u.u_exdata);
+               u.u_base = 0;
+               u.u_segflg = 2;
+               settprot(RW);
+               u.u_procp->p_flag |= SKEEP;
+               readi(ip);
+               u.u_procp->p_flag &= ~SKEEP;
+       }
+       settprot(RO);
+       u.u_segflg = 0;
+       xp->x_flag |= XWRIT;
+       xp->x_flag &= ~XLOAD;
+       xunlock(xp);
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Wait for xp to be unlocked if it is currently locked.
+ */
+xwait(xp)
+register struct text *xp;
+{
+
+       xlock(xp);
+       xunlock(xp);
+}
+
+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, p)
+register struct text *xp;
+register struct proc *p;
+{
+
+       if (xp==NULL || xp->x_ccount==0)
+               return;
+       xlock(xp);
+       if (--xp->x_ccount == 0) {
+               if (xp->x_flag & XWRIT) {
+                       vsswap(p, tptopte(p, 0), CTEXT, 0, xp->x_size, (struct dmap *)0);
+                       if (xp->x_flag & XPAGI)
+                               swap(p, xp->x_ptdaddr, (caddr_t)tptopte(p, 0),
+                                   xp->x_size * sizeof (struct pte),
+                                   B_WRITE, B_PAGET, swapdev, 0);
+                       xp->x_flag &= ~XWRIT;
+               } else
+                       xp->x_rssize -= vmemfree(tptopte(p, 0), xp->x_size);
+               if (xp->x_rssize != 0)
+                       panic("text rssize");
+       }
+       xunlink(p);
+       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;
+       vsxfree(xp, xp->x_size);
+       ip->i_flag &= ~ITEXT;
+       if (ip->i_flag&ILOCK)
+               ip->i_count--;
+       else
+               iput(ip);
+}
+
+/*
+ * Add a process to those sharing a text segment by
+ * getting the page tables and then linking to x_caddr.
+ */
+xlink(p)
+       register struct proc *p;
+{
+       register struct text *xp = p->p_textp;
+
+       if (xp == 0)
+               return;
+       vinitpt(p);
+       p->p_xlink = xp->x_caddr;
+       xp->x_caddr = p;
+       xp->x_ccount++;
+}
+
+xunlink(p)
+       register struct proc *p;
+{
+       register struct text *xp = p->p_textp;
+       register struct proc *q;
+
+       if (xp == 0)
+               return;
+       if (xp->x_caddr == p) {
+               xp->x_caddr = p->p_xlink;
+               p->p_xlink = 0;
+               return;
+       }
+       for (q = xp->x_caddr; q->p_xlink; q = q->p_xlink)
+               if (q->p_xlink == p) {
+                       q->p_xlink = p->p_xlink;
+                       p->p_xlink = 0;
+                       return;
+               }
+       panic("lost text");
+}
+
+/*
+ * Replace p by q in a text incore linked list.
+ * Used by vfork(), internally.
+ */
+xrepl(p, q)
+       struct proc *p, *q;
+{
+       register struct text *xp = q->p_textp;
+
+       if (xp == 0)
+               return;
+       xunlink(p);
+       q->p_xlink = xp->x_caddr;
+       xp->x_caddr = q;
+}
diff --git a/usr/src/sys/sys/vmdrum.c b/usr/src/sys/sys/vmdrum.c
new file mode 100644 (file)
index 0000000..4cbe3ee
--- /dev/null
@@ -0,0 +1,286 @@
+/*     vmdrum.c        4.1     11/9/80 */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/buf.h"
+#include "../h/text.h"
+#include "../h/map.h"
+#include "../h/pte.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+/*
+ * Expand the swap area for both the data and stack segments.
+ * If space is not available for both, retract and return 0.
+ */
+swpexpand(ds, ss, dmp, smp)
+       size_t ds, ss;
+       register struct dmap *dmp, *smp;
+{
+       register struct dmap *tmp;
+       register int ts;
+       size_t ods;
+
+       /*
+        * If dmap isn't growing, do smap first.
+        * This avoids anomalies if smap will try to grow and
+        * fail, which otherwise would shrink ds without expanding
+        * ss, a rather curious side effect!
+        */
+       if (dmp->dm_alloc > ds) {
+               tmp = dmp; ts = ds;
+               dmp = smp; ds = ss;
+               smp = tmp; ss = ts;
+       }
+       ods = dmp->dm_size;
+       if (vsexpand(ds, dmp, 0) == 0)
+               goto bad;
+       if (vsexpand(ss, smp, 0) == 0) {
+               (void) vsexpand(ods, dmp, 1);
+               goto bad;
+       }
+       return (1);
+
+bad:
+       u.u_error = ENOMEM;
+       return (0);
+}
+
+/*
+ * Expand or contract the virtual swap segment mapped
+ * by the argument diskmap so as to just allow the given size.
+ *
+ * FOR NOW CANT RELEASE UNLESS SHRINKING TO ZERO, SINCE PAGEOUTS MAY
+ * BE IN PROGRESS... TYPICALLY NEVER SHRINK ANYWAYS, SO DOESNT MATTER MUCH
+ */
+vsexpand(vssize, dmp, canshrink)
+       register size_t vssize;
+       register struct dmap *dmp;
+{
+       register int blk = DMMIN;
+       register int vsbase = 0;
+       register swblk_t *ip = dmp->dm_map;
+       size_t oldsize = dmp->dm_size;
+       size_t oldalloc = dmp->dm_alloc;
+
+       while (vsbase < oldalloc || vsbase < vssize) {
+               if (vsbase >= oldalloc) {
+                       *ip = malloc(swapmap, ctod(blk));
+                       if (*ip == 0) {
+                               dmp->dm_size = vsbase;
+                               if (vsexpand(oldsize, dmp, 1) == 0)
+                                       panic("vsexpand");
+                               return (0);
+                       }
+                       dmp->dm_alloc += blk;
+               } else if (vssize == 0 ||
+                   vsbase >= vssize && canshrink) {
+                       mfree(swapmap, ctod(blk), *ip);
+                       *ip = 0;
+                       dmp->dm_alloc -= blk;
+               }
+               vsbase += blk;
+               if (blk < DMMAX)
+                       blk *= 2;
+               ip++;
+               if (ip - dmp->dm_map > NDMAP)
+                       panic("vmdrum NDMAP");
+       }
+       dmp->dm_size = vssize;
+       return (1);
+}
+
+/*
+ * Allocate swap space for a text segment,
+ * in chunks of at most DMTEXT pages.
+ */
+vsxalloc(xp)
+       struct text *xp;
+{
+       register int blk;
+       register swblk_t *dp;
+       swblk_t vsbase;
+
+       if (xp->x_size > NXDAD * DMTEXT)
+               panic("vsxalloc");
+       dp = xp->x_daddr;
+       for (vsbase = 0; vsbase < xp->x_size; vsbase += DMTEXT) {
+               blk = xp->x_size - vsbase;
+               if (blk > DMTEXT)
+                       blk = DMTEXT;
+               if ((*dp++ = malloc(swapmap, blk)) == 0) {
+                       vsxfree(xp, vsbase);
+                       return (0);
+               }
+       }
+       if (xp->x_flag & XPAGI) {
+               xp->x_ptdaddr = malloc(swapmap, clrnd(ctopt(xp->x_size)));
+               if (xp->x_ptdaddr == 0) {
+                       vsxfree(xp, xp->x_size);
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
+ * Free the swap space of a text segment which
+ * has been allocated ts pages.
+ */
+vsxfree(xp, ts)
+       struct text *xp;
+       int ts;
+{
+       register int blk;
+       register swblk_t *dp;
+       swblk_t vsbase;
+
+       dp = xp->x_daddr;
+       for (vsbase = 0; vsbase < ts; vsbase += DMTEXT) {
+               blk = ts - vsbase;
+               if (blk > DMTEXT)
+                       blk = DMTEXT;
+               mfree(swapmap, blk, *dp);
+               *dp++ = 0;
+       }
+       if ((xp->x_flag&XPAGI) && xp->x_ptdaddr) {
+               mfree(swapmap, clrnd(ctopt(xp->x_size)), xp->x_ptdaddr);
+               xp->x_ptdaddr = 0;
+       }
+}
+
+/*
+ * Swap a segment of virtual memory to disk,
+ * by locating the contiguous dirty pte's
+ * and calling vschunk with each chunk.
+ */
+vsswap(p, pte, type, vsbase, vscount, dmp)
+       struct proc *p;
+       register struct pte *pte;
+       int type;
+       register int vsbase, vscount;
+       struct dmap *dmp;
+{
+       register int size = 0;
+
+       if (vscount % CLSIZE)
+               panic("vsswap");
+       for (;;) {
+               if (vscount == 0 || !dirtycl(pte)) {
+                       if (size) {
+                               vschunk(p, vsbase, size, type, dmp);
+                               vsbase += size;
+                               size = 0;
+                       }
+                       if (vscount == 0)
+                               return;
+                       vsbase += CLSIZE;
+                       if (pte->pg_fod == 0 && pte->pg_pfnum)
+                               if (type == CTEXT)
+                                       p->p_textp->x_rssize -= vmemfree(pte, CLSIZE);
+                               else
+                                       p->p_rssize -= vmemfree(pte, CLSIZE);
+               } else {
+                       size += CLSIZE;
+                       mwait(pte->pg_pfnum);
+                       if (anycl(pte, pg_m))
+                               zapcl(pte, pg_vreadm) = 1;
+               }
+               vscount -= CLSIZE;
+               if (type == CSTACK)
+                       pte -= CLSIZE;
+               else
+                       pte += CLSIZE;
+       }
+}
+
+vschunk(p, base, size, type, dmp)
+       register struct proc *p;
+       register int base, size;
+       int type;
+       struct dmap *dmp;
+{
+       register struct pte *pte;
+       struct dblock db;
+       unsigned v;
+
+       if (type == CTEXT) {
+               while (size > 0) {
+                       db.db_size = DMTEXT - base % DMTEXT;
+                       if (db.db_size > size)
+                               db.db_size = size;
+                       swap(p, p->p_textp->x_daddr[base/DMTEXT] + base%DMTEXT,
+                           ptob(tptov(p, base)), ctob(db.db_size),
+                           B_WRITE, 0, swapdev, 0);
+                       p->p_textp->x_rssize -=
+                           vmemfree(tptopte(p, base), db.db_size);
+                       base += db.db_size;
+                       size -= db.db_size;
+               }
+               return;
+       }
+       do {
+               vstodb(base, size, dmp, &db, type == CSTACK);
+               v = type==CSTACK ? sptov(p, base+db.db_size-1) : dptov(p, base);
+               swap(p, db.db_base, ptob(v), ctob(db.db_size), B_WRITE, 0, swapdev, 0);
+               pte = type==CSTACK ? sptopte(p, base+db.db_size-1) : dptopte(p, base);
+               p->p_rssize -= vmemfree(pte, db.db_size);
+               base += db.db_size;
+               size -= db.db_size;
+       } while (size != 0);
+}
+
+/*
+ * Given a base/size pair in virtual swap area,
+ * return a physical base/size pair which is the
+ * (largest) initial, physically contiguous block.
+ */
+vstodb(vsbase, vssize, dmp, dbp, rev)
+       register int vsbase, vssize;
+       struct dmap *dmp;
+       register struct dblock *dbp;
+{
+       register int blk = DMMIN;
+       register swblk_t *ip = dmp->dm_map;
+
+       if (vsbase < 0 || vssize < 0 || vsbase + vssize > dmp->dm_size)
+               panic("vstodb");
+       while (vsbase >= blk) {
+               vsbase -= blk;
+               if (blk < DMMAX)
+                       blk *= 2;
+               ip++;
+       }
+       if (*ip + blk > nswap)
+               panic("vstodb *ip");
+       dbp->db_size = imin(vssize, blk - vsbase);
+       dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
+}
+
+/*
+ * Convert a virtual page number 
+ * to its corresponding disk block number.
+ * Used in pagein/pageout to initiate single page transfers.
+ */
+swblk_t
+vtod(p, v, dmap, smap)
+       register struct proc *p;
+       unsigned v;
+       struct dmap *dmap, *smap;
+{
+       struct dblock db;
+       int tp;
+
+       if (isatsv(p, v)) {
+               tp = vtotp(p, v);
+               return (p->p_textp->x_daddr[tp/DMTEXT] + tp%DMTEXT);
+       }
+       if (isassv(p, v))
+               vstodb(vtosp(p, v), 1, smap, &db, 1);
+       else
+               vstodb(vtodp(p, v), 1, dmap, &db, 0);
+       return (db.db_base);
+}
diff --git a/usr/src/sys/sys/vmmon.c b/usr/src/sys/sys/vmmon.c
new file mode 100644 (file)
index 0000000..5e66a5e
--- /dev/null
@@ -0,0 +1,40 @@
+/*     vmmon.c 4.1     11/9/80 */
+
+#ifdef PGINPROF
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/vmmon.h"
+
+int pmonmin = PMONMIN;
+int pres = PRES;
+int rmonmin = RMONMIN;
+int rres = RRES;
+
+vmsizmon()
+{
+       register int i;
+
+       i = (u.u_dsize / DRES) < NDMON ? (u.u_dsize / DRES):NDMON;
+       dmon[i] += u.u_vm.vm_utime - u.u_outime;
+
+       i = (u.u_ssize / SRES) < NSMON ? (u.u_ssize / SRES):NSMON;
+       smon[i] += u.u_vm.vm_utime - u.u_outime;
+       u.u_outime = u.u_vm.vm_utime;
+}
+
+vmfltmon(hist, atime, amin, res, nmax)
+       register unsigned int *hist;
+       register int atime, amin, res, nmax;
+{
+       register int i;
+
+       i = (atime - amin) / res;
+       if (i>=0 && i<nmax)
+               hist[i+1]++;
+       else 
+               i<0 ? hist[0]++ : hist[nmax+1]++;
+}
+#endif
diff --git a/usr/src/sys/sys/vmsched.c b/usr/src/sys/sys/vmsched.c
new file mode 100644 (file)
index 0000000..10617fe
--- /dev/null
@@ -0,0 +1,437 @@
+/*     vmsched.c       4.1     11/9/80 */
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/seg.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/proc.h"
+#include "../h/text.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+int    maxpgio = MAXPGIO;
+int    maxslp = MAXSLP;
+int    minfree = MINFREE;
+int    desfree = DESFREE;
+int    lotsfree = 0;           /* set to LOTSFREE in main unless adbed */
+int    saferss = SAFERSS;
+int    slowscan = SLOWSCAN;
+int    fastscan = FASTSCAN;
+int    klin = KLIN;
+int    klout = KLOUT;
+int    multprog = -1;          /* so we don't count process 2 */
+
+double avenrun[3];             /* load average, of runnable procs */
+
+/*
+ * 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.
+ * If the paging rate is too high, or the average free memory
+ * is very low, then we do not consider swapping anyone in,
+ * but rather look for someone to swap out.
+ *
+ * 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 DOESN'T ACCOUNT FOR PAGE TABLE SIZE IN CALCULATIONS.
+ */
+
+#define        swappable(p) \
+       (((p)->p_flag&(SSYS|SLOCK|SULOCK|SLOAD|SPAGE|SKEEP|SWEXIT|SPHYSIO))==SLOAD)
+
+/* insure non-zero */
+#define        nz(x)   (x != 0 ? x : 1)
+
+#define        NBIG    4
+#define        MAXNBIG 10
+int    nbig = NBIG;
+
+struct bigp {
+       struct  proc *bp_proc;
+       int     bp_pri;
+       struct  bigp *bp_link;
+} bigp[MAXNBIG], bplist;
+
+sched()
+{
+       register struct proc *rp, *p, *inp;
+       int outpri, inpri, rppri;
+       int sleeper, desperate, deservin, needs, divisor;
+       register struct bigp *bp, *nbp;
+       int biggot, gives;
+
+       /*
+        * Check if paging rate is too high, or average of
+        * free list very low and if so, adjust multiprogramming
+        * load by swapping someone out.
+        *
+        * Avoid glitches: don't hard swap the only process,
+        * and don't swap based on paging rate if there is a reasonable
+        * amount of free memory.
+        */
+loop:
+       (void) spl6();
+       deservin = 0;
+       sleeper = 0;
+       p = 0;
+       if (kmapwnt || (multprog > 1 && avefree < desfree &&
+           (rate.v_pgin + rate.v_pgout > maxpgio || avefree < minfree))) {
+               desperate = 1;
+               goto hardswap;
+       }
+       desperate = 0;
+       /*
+        * Not desperate for core,
+        * look for someone who deserves to be brought in.
+        */
+       outpri = -20000;
+       for (rp = &proc[0]; rp < &proc[NPROC]; rp++) switch(rp->p_stat) {
+
+       case SRUN:
+               if ((rp->p_flag&SLOAD) == 0) {
+                       rppri = rp->p_time - rp->p_swrss / nz((maxpgio/2) * CLSIZE) +
+                           rp->p_slptime - (rp->p_nice-NZERO)*8;
+                       if (rppri > outpri) {
+                               if (rp->p_poip)
+                                       continue;
+                               if (rp->p_textp && rp->p_textp->x_poip)
+                                       continue;
+                               p = rp;
+                               outpri = rppri;
+                       }
+               }
+               continue;
+
+       case SSLEEP:
+       case SSTOP:
+               if ((freemem < desfree || rp->p_rssize == 0) &&
+                   rp->p_slptime > maxslp &&
+                   (!rp->p_textp || (rp->p_textp->x_flag&XLOCK)==0) &&
+                   swappable(rp)) {
+                       /*
+                        * Kick out deadwood.
+                        * FOLLOWING 3 LINES MUST BE AT spl6().
+                        */
+                       rp->p_flag &= ~SLOAD;
+                       if (rp->p_stat == SRUN)
+                               remrq(rp);
+                       (void) swapout(rp, rp->p_dsize, rp->p_ssize);
+                       goto loop;
+               }
+               continue;
+       }
+
+       /*
+        * No one wants in, so nothing to do.
+        */
+       if (outpri == -20000) {
+               runout++;
+               sleep((caddr_t)&runout, PSWP);
+               goto loop;
+       }
+       (void) spl0();
+       /*
+        * Decide how deserving this guy is.  If he is deserving
+        * we will be willing to work harder to bring him in.
+        * Needs is an estimate of how much core he will need.
+        * If he has been out for a while, then we will
+        * bring him in with 1/2 the core he will need, otherwise
+        * we are conservative.
+        */
+       deservin = 0;
+       divisor = 1;
+       if (outpri > maxslp/2) {
+               deservin = 1;
+               divisor = 2;
+       }
+       needs = p->p_swrss;
+       if (p->p_textp && p->p_textp->x_ccount == 0)
+               needs += p->p_textp->x_swrss;
+       if (freemem - deficit > needs / divisor) {
+               deficit += needs;
+               if (swapin(p))
+                       goto loop;
+               deficit -= imin(needs, deficit);
+       }
+
+hardswap:
+       /*
+        * Need resources (kernel map or memory), swap someone out.
+        * Select the nbig largest jobs, then the oldest of these
+        * is ``most likely to get booted.''
+        */
+       (void) spl6();
+       inp = p;
+       sleeper = 0;
+       if (nbig > MAXNBIG)
+               nbig = MAXNBIG;
+       if (nbig < 1)
+               nbig = 1;
+       biggot = 0;
+       bplist.bp_link = 0;
+       for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {
+               if (!swappable(rp))
+                       continue;
+               if (rp->p_stat==SZOMB)
+                       continue;
+               if (rp == inp)
+                       continue;
+               if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
+                       continue;
+               if (rp->p_slptime > maxslp &&
+                   (rp->p_stat==SSLEEP&&rp->p_pri>PZERO||rp->p_stat==SSTOP)) {
+                       if (sleeper < rp->p_slptime) {
+                               p = rp;
+                               sleeper = rp->p_slptime;
+                       }
+               } else if (!sleeper && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) {
+                       rppri = rp->p_rssize;
+                       if (rp->p_textp)
+                               rppri += rp->p_textp->x_rssize/rp->p_textp->x_ccount;
+                       if (biggot < nbig)
+                               nbp = &bigp[biggot++];
+                       else {
+                               nbp = bplist.bp_link;
+                               if (nbp->bp_pri > rppri)
+                                       continue;
+                               bplist.bp_link = nbp->bp_link;
+                       }
+                       for (bp = &bplist; bp->bp_link; bp = bp->bp_link)
+                               if (rppri < bp->bp_link->bp_pri)
+                                       break;
+                       nbp->bp_link = bp->bp_link;
+                       bp->bp_link = nbp;
+                       nbp->bp_pri = rppri;
+                       nbp->bp_proc = rp;
+               }
+       }
+       if (!sleeper) {
+               p = NULL;
+               inpri = -1000;
+               for (bp = bplist.bp_link; bp; bp = bp->bp_link) {
+                       rp = bp->bp_proc;
+                       rppri = rp->p_time+rp->p_nice-NZERO;
+                       if (rppri >= inpri) {
+                               p = rp;
+                               inpri = rppri;
+                       }
+               }
+       }
+       /*
+        * If we found a long-time sleeper, or we are desperate and
+        * found anyone to swap out, or if someone deserves to come
+        * in and we didn't find a sleeper, but found someone who
+        * has been in core for a reasonable length of time, then
+        * we kick the poor luser out.
+        */
+       if (sleeper || desperate && p || deservin && inpri > maxslp) {
+               p->p_flag &= ~SLOAD;
+               if (p->p_stat == SRUN)
+                       remrq(p);
+               if (desperate) {
+                       /*
+                        * Want to give this space to the rest of
+                        * the processes in core so give them a chance
+                        * by increasing the deficit.
+                        */
+                       gives = p->p_rssize;
+                       if (p->p_textp)
+                               gives += p->p_textp->x_rssize / p->p_textp->x_ccount;
+                       deficit += gives;
+               } else
+                       gives = 0;      /* someone else taketh away */
+               if (swapout(p, p->p_dsize, p->p_ssize) == 0)
+                       deficit -= imin(gives, deficit);
+               goto loop;
+       }
+       /*
+        * Want to swap someone in, but can't
+        * so wait on runin.
+        */
+       (void) spl6();
+       runin++;
+       sleep((caddr_t)&runin, PSWP);
+       goto loop;
+}
+
+vmmeter()
+{
+       register unsigned *cp, *rp, *sp;
+
+       deficit -= imin(deficit, imax(deficit / 10, maxpgio / 2));
+       ave(avefree, freemem, 5);
+       /* v_pgin is maintained by clock.c */
+       cp = &cnt.v_first; rp = &rate.v_first; sp = &sum.v_first;
+       while (cp <= &cnt.v_last) {
+               ave(*rp, *cp, 5);
+               *sp += *cp;
+               *cp = 0;
+               rp++, cp++, sp++;
+       }
+       if (time % 5 == 0) {
+               vmtotal();
+               rate.v_swpin = cnt.v_swpin;
+               sum.v_swpin += cnt.v_swpin;
+               cnt.v_swpin = 0;
+               rate.v_swpout = cnt.v_swpout;
+               sum.v_swpout += cnt.v_swpout;
+               cnt.v_swpout = 0;
+       }
+       if (avefree < minfree && runout || proc[0].p_slptime > maxslp/2) {
+               runout = 0;
+               runin = 0;
+               wakeup((caddr_t)&runin);
+               wakeup((caddr_t)&runout);
+       }
+}
+
+vmpago()
+{
+       register int vavail;
+       register int scanrate;
+
+       /*
+        * Compute new rate for clock; if
+        * nonzero, restart clock.
+        * Rate ranges linearly from one rev per
+        * slowscan seconds when there is lotsfree memory
+        * available to one rev per fastscan seconds when
+        * there is no memory available.
+        */
+       nscan = desscan = 0;
+       vavail = freemem - deficit;
+       if (vavail < 0)
+               vavail = 0;
+       if (freemem >= lotsfree)
+               return;
+       scanrate = (slowscan * vavail + fastscan * (lotsfree - vavail)) / nz(lotsfree);
+       desscan = LOOPSIZ / nz(scanrate);
+       /*
+        * DIVIDE BY 4 TO ACCOUNT FOR RUNNING 4* A SECOND (see clock.c)
+        */
+       desscan /= 4;
+       wakeup((caddr_t)&proc[2]);
+}
+
+vmtotal()
+{
+       register struct proc *p;
+       register struct text *xp;
+       int nrun = 0;
+
+       total.t_vmtxt = 0;
+       total.t_avmtxt = 0;
+       total.t_rmtxt = 0;
+       total.t_armtxt = 0;
+       for (xp = &text[0]; xp < &text[NTEXT]; xp++)
+               if (xp->x_iptr) {
+                       total.t_vmtxt += xp->x_size;
+                       total.t_rmtxt += xp->x_rssize;
+                       for (p = xp->x_caddr; p; p = p->p_xlink)
+                       switch (p->p_stat) {
+
+                       case SSTOP:
+                       case SSLEEP:
+                               if (p->p_slptime >= maxslp)
+                                       continue;
+                               /* fall into... */
+
+                       case SRUN:
+                       case SIDL:
+                               total.t_avmtxt += xp->x_size;
+                               total.t_armtxt += xp->x_rssize;
+                               goto next;
+                       }
+next:
+                       ;
+               }
+       total.t_vm = 0;
+       total.t_avm = 0;
+       total.t_rm = 0;
+       total.t_arm = 0;
+       total.t_rq = 0;
+       total.t_dw = 0;
+       total.t_pw = 0;
+       total.t_sl = 0;
+       total.t_sw = 0;
+       for (p = &proc[0]; p < &proc[NPROC]; p++) {
+               if (p->p_flag & SSYS)
+                       continue;
+               if (p->p_stat) {
+                       total.t_vm += p->p_dsize + p->p_ssize;
+                       total.t_rm += p->p_rssize;
+                       switch (p->p_stat) {
+
+                       case SSLEEP:
+                       case SSTOP:
+                               if (p->p_pri <= PZERO)
+                                       nrun++;
+                               if (p->p_flag & SPAGE)
+                                       total.t_pw++;
+                               else if (p->p_flag & SLOAD) {
+                                       if (p->p_pri <= PZERO)
+                                               total.t_dw++;
+                                       else if (p->p_slptime < maxslp)
+                                               total.t_sl++;
+                               } else if (p->p_slptime < maxslp)
+                                       total.t_sw++;
+                               if (p->p_slptime < maxslp)
+                                       goto active;
+                               break;
+
+                       case SRUN:
+                       case SIDL:
+                               nrun++;
+                               if (p->p_flag & SLOAD)
+                                       total.t_rq++;
+                               else
+                                       total.t_sw++;
+active:
+                               total.t_avm += p->p_dsize + p->p_ssize;
+                               total.t_arm += p->p_rssize;
+                               break;
+                       }
+               }
+       }
+       total.t_vm += total.t_vmtxt;
+       total.t_avm += total.t_avmtxt;
+       total.t_rm += total.t_rmtxt;
+       total.t_arm += total.t_armtxt;
+       total.t_free = avefree;
+       loadav(avenrun, nrun);
+}
+
+/*
+ * Constants for averages over 1, 5, and 15 minutes
+ * when sampling at 5 second intervals.
+ */
+double cexp[3] = {
+       0.9200444146293232,     /* exp(-1/12) */
+       0.9834714538216174,     /* exp(-1/60) */
+       0.9944598480048967,     /* exp(-1/180) */
+};
+
+/*
+ * Compute a tenex style load average of a quantity on
+ * 1, 5 and 15 minute intervals.
+ */
+loadav(avg, n)
+       register double *avg;
+       int n;
+{
+       register int i;
+
+       for (i = 0; i < 3; i++)
+               avg[i] = cexp[i] * avg[i] + n * (1.0 - cexp[i]);
+}
diff --git a/usr/src/sys/sys/vmsys.c b/usr/src/sys/sys/vmsys.c
new file mode 100644 (file)
index 0000000..c003c8b
--- /dev/null
@@ -0,0 +1,191 @@
+/*     vmsys.c 4.1     11/9/80 */
+
+#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/file.h"
+#include "../h/inode.h"
+#include "../h/vm.h"
+#include "../h/buf.h"
+#include "../h/pte.h"
+#include "../h/cmap.h"
+#include "../h/tty.h"
+#include "../h/mtpr.h"
+#include "../h/vlimit.h"
+
+vfork()
+{
+
+       fork1(1);
+}
+
+vread()
+{
+
+       vrdwr(FREAD);
+}
+
+vwrite()
+{
+
+       vrdwr(FWRITE);
+}
+
+segalloc()
+{
+
+       u.u_error = EIO;
+}
+
+segfree()
+{
+
+       u.u_error = EIO;
+}
+
+segsync()
+{
+
+       u.u_error = EIO;
+}
+
+int    both;
+
+vadvise()
+{
+       register struct a {
+               int     anom;
+       } *uap;
+       register struct proc *rp = u.u_procp;
+       int oanom = rp->p_flag & (SANOM|SUANOM);
+       register struct pte *pte;
+       register struct cmap *c;
+       register int i;
+
+       uap = (struct a *)u.u_ap;
+       rp->p_flag &= ~SUANOM;
+       if (uap->anom)
+               rp->p_flag |= SUANOM;
+       if (both || oanom && (rp->p_flag & (SANOM|SUANOM)) == 0) {
+               for (i = 0; i < rp->p_dsize; i += CLSIZE) {
+                       pte = dptopte(rp, i);
+                       if (pte->pg_v) {
+                               c = &cmap[pgtocm(pte->pg_pfnum)];
+                               if (c->c_lock)
+                                       continue;
+                               pte->pg_v = 0;
+                               if (anycl(pte, pg_m))
+                                       pte->pg_m = 1;
+                               distcl(pte);
+                       }
+               }
+               mtpr(TBIA, 0);
+       }
+}
+
+vtimes()
+{
+       register struct a {
+               struct  vtimes *par_vm;
+               struct  vtimes *ch_vm;
+       } *uap = (struct a *)u.u_ap;
+
+       if (uap->par_vm == 0)
+               goto onlych;
+       if (copyout((caddr_t)&u.u_vm, (caddr_t)uap->par_vm,
+           sizeof(struct vtimes)) < 0)
+               u.u_error = EFAULT;
+onlych:
+       if (uap->ch_vm == 0)
+               return;
+       if (copyout((caddr_t)&u.u_cvm, (caddr_t)uap->ch_vm,
+           sizeof(struct vtimes)) < 0)
+               u.u_error = EFAULT;
+}
+
+vmsadd(vp, wp)
+       register struct vtimes *vp, *wp;
+{
+
+       vp->vm_utime += wp->vm_utime;
+       vp->vm_stime += wp->vm_stime;
+       vp->vm_nswap += wp->vm_nswap;
+       vp->vm_idsrss += wp->vm_idsrss;
+       vp->vm_ixrss += wp->vm_ixrss;
+       if (vp->vm_maxrss < wp->vm_maxrss)
+               vp->vm_maxrss = wp->vm_maxrss;
+       vp->vm_majflt += wp->vm_majflt;
+       vp->vm_minflt += wp->vm_minflt;
+       vp->vm_inblk += wp->vm_inblk;
+       vp->vm_oublk += wp->vm_oublk;
+}
+
+/*
+ * Revoke access the current tty by all processes.
+ * Used only by the super-user in init
+ * to give ``clean'' terminals at login.
+ */
+vhangup()
+{
+       register struct file *fp;
+       register struct inode *ip;
+
+       if (!suser())
+               return;
+       if (u.u_ttyp == NULL)
+               return;
+       for (fp = &file[0]; fp < &file[NFILE]; fp++) {
+               if (fp->f_count==0)
+                       continue;
+               ip = fp->f_inode;
+               if ((ip->i_mode & IFMT) != IFCHR)
+                       continue;
+               if (ip->i_un.i_rdev != u.u_ttyd)
+                       continue;
+               fp->f_flag &= ~(FREAD|FWRITE);
+       }
+       if ((u.u_ttyp->t_state) & ISOPEN)
+               gsignal(u.u_ttyp->t_pgrp, SIGHUP);
+}
+
+/*
+ * Affect per-process limits.
+ * To just return old limit, specify negative new limit.
+ */
+vlimit()
+{
+       register struct a {
+               unsigned which;
+               int     limit;
+       } *uap;
+
+       uap = (struct a *)u.u_ap;
+       if (uap->which > NLIMITS) {
+               u.u_error = EINVAL;
+               return;
+       }
+       u.u_r.r_val1 = u.u_limit[uap->which];
+       if (uap->limit < 0)
+               return;
+       switch (uap->which) {
+
+       case LIM_DATA:
+               if (uap->limit > ctob(MAXDSIZ))
+                       uap->limit = ctob(MAXDSIZ);
+               break;
+
+       case LIM_STACK:
+               if (uap->limit > ctob(MAXSSIZ))
+                       uap->limit = ctob(MAXSSIZ);
+               break;
+       }
+       if (u.u_limit[LIM_NORAISE] && uap->limit > u.u_limit[uap->which] &&
+           !suser()) {
+               u.u_error = EACCES;
+               return;
+       }
+       u.u_limit[uap->which] = uap->limit;
+}
diff --git a/usr/src/sys/sys/vmsysent.c b/usr/src/sys/sys/vmsysent.c
new file mode 100644 (file)
index 0000000..d317ab3
--- /dev/null
@@ -0,0 +1,79 @@
+/*     vmsysent.c      4.1     11/9/80 */
+
+/*
+ * This table is the switch used to transfer
+ * to the appropriate routine for processing a vmunix special system call.
+ * Each row contains the number of arguments expected
+ * and a pointer to the routine.
+ */
+
+/*
+ * Executing system call 64 indirect will tell whether the current
+ * system is a vmunix, since this will give an error indication on
+ * a non-virtual system, but just return without error on a virtual system.
+ */
+#define        isvmsys nullsys
+       0, 0, isvmsys,                  /* 64 +0 = isvmsys */
+       0, 0, nosys,                    /* 64 +1 = nosys */
+       0, 0, vfork,                    /* 64 +2 = vfork */
+       3, 0, vread,                    /* 64 +3 = vread */
+       3, 0, vwrite,                   /* 64 +4 = vwrite */
+       3, 0, segalloc,                 /* 64 +5 = segalloc */
+       1, 0, segfree,                  /* 64 +6 = segfree */
+       1, 0, segsync,                  /* 64 +7 = segsync */
+       1, 0, vadvise,                  /* 64 +8 = vadvise */
+       0, 0, nosys,                    /* 64 +9 = nosys */
+       0, 0, nosys,                    /* 64+10 = nosys */
+       0, 0, nosys,                    /* 64+11 = nosys */
+       1, 0, vhangup,                  /* 64+12 = vhangup */
+       2, 0, vlimit,                   /* 64+13 = vlimit */
+       0, 0, nosys,                    /* 64+14 = nosys */
+       0, 0, nosys,                    /* 64+15 = nosys */
+       0, 0, nosys,                    /* 64+16 = nosys */
+       0, 0, nosys,                    /* 64+17 = nosys */
+       0, 0, nosys,                    /* 64+18 = nosys */
+       0, 0, nosys,                    /* 64+19 = nosys */
+       0, 0, nosys,                    /* 64+20 = nosys */
+       1, 0, vswapon,                  /* 64+21 = vswapon */
+       0, 0, nosys,                    /* 64+22 = nosys */
+       0, 0, nosys,                    /* 64+23 = nosys */
+       0, 0, nosys,                    /* 64+24 = nosys */
+       0, 0, nosys,                    /* 64+25 = nosys */
+       0, 0, nosys,                    /* 64+26 = nosys */
+       0, 0, nosys,                    /* 64+27 = nosys */
+       0, 0, nosys,                    /* 64+28 = nosys */
+       0, 0, nosys,                    /* 64+29 = nosys */
+       0, 0, nosys,                    /* 64+30 = nosys */
+       0, 0, nosys,                    /* 64+31 = nosys */
+       0, 0, nosys,                    /* 64+32 = nosys */
+       0, 0, nosys,                    /* 64+33 = nosys */
+       0, 0, nosys,                    /* 64+34 = nosys */
+       0, 0, nosys,                    /* 64+35 = nosys */
+       0, 0, nosys,                    /* 64+36 = nosys */
+       0, 0, nosys,                    /* 64+37 = nosys */
+       0, 0, nosys,                    /* 64+38 = nosys */
+       0, 0, nosys,                    /* 64+39 = nosys */
+       0, 0, nosys,                    /* 64+40 = nosys */
+       0, 0, nosys,                    /* 64+41 = nosys */
+       0, 0, nosys,                    /* 64+42 = nosys */
+       2, 0, vtimes,                   /* 64+43 = vtimes */
+       0, 0, nosys,                    /* 64+44 = nosys */
+       0, 0, nosys,                    /* 64+45 = nosys */
+       0, 0, nosys,                    /* 64+46 = nosys */
+       0, 0, nosys,                    /* 64+47 = nosys */
+       0, 0, nosys,                    /* 64+48 = nosys */
+       0, 0, nosys,                    /* 64+49 = nosys */
+       0, 0, nosys,                    /* 64+50 = nosys */
+       0, 0, nosys,                    /* 64+51 = nosys */
+       0, 0, nosys,                    /* 64+52 = nosys */
+       0, 0, nosys,                    /* 64+53 = nosys */
+       0, 0, nosys,                    /* 64+54 = nosys */
+       0, 0, nosys,                    /* 64+55 = nosys */
+       0, 0, nosys,                    /* 64+56 = nosys */
+       0, 0, nosys,                    /* 64+57 = nosys */
+       0, 0, nosys,                    /* 64+58 = nosys */
+       0, 0, nosys,                    /* 64+59 = nosys */
+       0, 0, nosys,                    /* 64+60 = nosys */
+       0, 0, nosys,                    /* 64+61 = nosys */
+       0, 0, nosys,                    /* 64+62 = nosys */
+       0, 0, nosys,                    /* 64+63 = nosys */