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