Add original unix v6

This commit is contained in:
memnoth
2018-01-27 22:35:41 +09:00
commit 2c7099ee50
664 changed files with 106254 additions and 0 deletions
+314
View File
@@ -0,0 +1,314 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../filsys.h"
#include "../conf.h"
#include "../buf.h"
#include "../inode.h"
#include "../user.h"
/*
* 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 *cp, *bp;
(*bdevsw[rootdev.d_major].d_open)(rootdev, 1);
bp = bread(rootdev, 1);
cp = getblk(NODEV);
if(u.u_error)
panic("iinit");
bcopy(bp->b_addr, cp->b_addr, 256);
brelse(bp);
mount[0].m_bufp = cp;
mount[0].m_dev = rootdev;
cp = cp->b_addr;
cp->s_flock = 0;
cp->s_ilock = 0;
cp->s_ronly = 0;
time[0] = cp->s_time[0];
time[1] = cp->s_time[1];
}
/*
* alloc will obtain the next available
* free disk block from the free list of
* the specified device.
* The super block has up to 100 remembered
* free blocks; the last of these is read to
* obtain 100 more . . .
*
* no space on dev x/y -- when
* the free list is exhausted.
*/
alloc(dev)
{
int bno;
register *bp, *ip, *fp;
fp = getfs(dev);
while(fp->s_flock)
sleep(&fp->s_flock, PINOD);
do {
if(fp->s_nfree <= 0)
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);
ip = bp->b_addr;
fp->s_nfree = *ip++;
bcopy(ip, fp->s_free, 100);
brelse(bp);
fp->s_flock = 0;
wakeup(&fp->s_flock);
}
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)
{
register *fp, *bp, *ip;
fp = getfs(dev);
fp->s_fmod = 1;
while(fp->s_flock)
sleep(&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 >= 100) {
fp->s_flock++;
bp = getblk(dev, bno);
ip = bp->b_addr;
*ip++ = fp->s_nfree;
bcopy(fp->s_free, ip, 100);
fp->s_nfree = 0;
bwrite(bp);
fp->s_flock = 0;
wakeup(&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(afp, abn, dev)
{
register struct filsys *fp;
register char *bn;
fp = afp;
bn = abn;
if (bn < fp->s_isize+2 || 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
* 100 spare I nodes in the
* super block. When this runs out,
* a linear search through the
* I list is instituted to pick
* up 100 more.
*/
ialloc(dev)
{
register *fp, *bp, *ip;
int i, j, k, ino;
fp = getfs(dev);
while(fp->s_ilock)
sleep(&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(bp = &ip->i_mode; bp < &ip->i_addr[8];)
*bp++ = 0;
fp->s_fmod = 1;
return(ip);
}
/*
* Inode was allocated after all.
* Look some more.
*/
iput(ip);
goto loop;
}
fp->s_ilock++;
ino = 0;
for(i=0; i<fp->s_isize; i++) {
bp = bread(dev, i+2);
ip = bp->b_addr;
for(j=0; j<256; j=+16) {
ino++;
if(ip[j] != 0)
continue;
for(k=0; k<NINODE; k++)
if(dev==inode[k].i_dev && ino==inode[k].i_number)
goto cont;
fp->s_inode[fp->s_ninode++] = ino;
if(fp->s_ninode >= 100)
break;
cont:;
}
brelse(bp);
if(fp->s_ninode >= 100)
break;
}
fp->s_ilock = 0;
wakeup(&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 100 I nodes in the super
* block and throws away any more.
*/
ifree(dev, ino)
{
register *fp;
fp = getfs(dev);
if(fp->s_ilock)
return;
if(fp->s_ninode >= 100)
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"
*/
getfs(dev)
{
register struct mount *p;
register char *n1, *n2;
for(p = &mount[0]; p < &mount[NMOUNT]; p++)
if(p->m_bufp != NULL && p->m_dev == dev) {
p = p->m_bufp->b_addr;
n1 = p->s_nfree;
n2 = p->s_ninode;
if(n1 > 100 || n2 > 100) {
prdev("bad count", dev);
p->s_nfree = 0;
p->s_ninode = 0;
}
return(p);
}
panic("no fs");
}
/*
* 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 *bp;
if(updlock)
return;
updlock++;
for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if(mp->m_bufp != NULL) {
ip = mp->m_bufp->b_addr;
if(ip->s_fmod==0 || ip->s_ilock!=0 ||
ip->s_flock!=0 || ip->s_ronly!=0)
continue;
bp = getblk(mp->m_dev, 1);
ip->s_fmod = 0;
ip->s_time[0] = time[0];
ip->s_time[1] = time[1];
bcopy(ip, bp->b_addr, 256);
bwrite(bp);
}
for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
if((ip->i_flag&ILOCK) == 0) {
ip->i_flag =| ILOCK;
iupdat(ip, time);
prele(ip);
}
updlock = 0;
bflush(NODEV);
}
+173
View File
@@ -0,0 +1,173 @@
#
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../proc.h"
#define UMODE 0170000
#define SCHMAG 10
/*
* clock is called straight from
* the real time clock interrupt.
*
* Functions:
* reprime clock
* copy *switches to display
* implement callouts
* maintain user/system times
* maintain date
* profile
* tout wakeup (sys sleep)
* lightning bolt wakeup (every 4 sec)
* alarm clock signals
* jab the scheduler
*/
clock(dev, sp, r1, nps, r0, pc, ps)
{
register struct callo *p1, *p2;
register struct proc *pp;
/*
* restart clock
*/
*lks = 0115;
/*
* display register
*/
display();
/*
* callouts
* if none, just return
* else update first non-zero time
*/
if(callout[0].c_func == 0)
goto out;
p2 = &callout[0];
while(p2->c_time<=0 && p2->c_func!=0)
p2++;
p2->c_time--;
/*
* if ps is high, just return
*/
if((ps&0340) != 0)
goto out;
/*
* callout
*/
spl5();
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:
if((ps&UMODE) == UMODE) {
u.u_utime++;
if(u.u_prof[3])
incupc(pc, u.u_prof);
} else
u.u_stime++;
pp = u.u_procp;
if(++pp->p_cpu == 0)
pp->p_cpu--;
if(++lbolt >= HZ) {
if((ps&0340) != 0)
return;
lbolt =- HZ;
if(++time[1] == 0)
++time[0];
spl1();
if(time[1]==tout[1] && time[0]==tout[0])
wakeup(tout);
if((time[1]&03) == 0) {
runrun++;
wakeup(&lbolt);
}
for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
if (pp->p_stat) {
if(pp->p_time != 127)
pp->p_time++;
if((pp->p_cpu & 0377) > SCHMAG)
pp->p_cpu =- SCHMAG; else
pp->p_cpu = 0;
if(pp->p_pri > PUSER)
setpri(pp);
}
if(runin!=0) {
runin = 0;
wakeup(&runin);
}
if((ps&UMODE) == UMODE) {
u.u_ar0 = &r0;
if(issig())
psig();
setpri(u.u_procp);
}
}
}
/*
* 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.
*/
timeout(fun, arg, tim)
{
register struct callo *p1, *p2;
register t;
int s;
t = tim;
s = PS->integ;
p1 = &callout[0];
spl7();
while(p1->c_func != 0 && p1->c_time <= t) {
t =- p1->c_time;
p1++;
}
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;
PS->integ = s;
}
+258
View File
@@ -0,0 +1,258 @@
#
/*
*/
#include "../param.h"
#include "../user.h"
#include "../filsys.h"
#include "../file.h"
#include "../conf.h"
#include "../inode.h"
#include "../reg.h"
/*
* Convert a user supplied
* file descriptor into a pointer
* to a file structure.
* Only task is to check range
* of the descriptor.
*/
getf(f)
{
register *fp, rf;
rf = f;
if(rf<0 || rf>=NOFILE)
goto bad;
fp = u.u_ofile[rf];
if(fp != NULL)
return(fp);
bad:
u.u_error = EBADF;
return(NULL);
}
/*
* Internal form of close.
* Decrement reference count on
* file structure and call closei
* on last closef.
* Also make sure the pipe protocol
* does not constipate.
*/
closef(fp)
int *fp;
{
register *rfp, *ip;
rfp = fp;
if(rfp->f_flag&FPIPE) {
ip = rfp->f_inode;
ip->i_mode =& ~(IREAD|IWRITE);
wakeup(ip+1);
wakeup(ip+2);
}
if(rfp->f_count <= 1)
closei(rfp->f_inode, rfp->f_flag&FWRITE);
rfp->f_count--;
}
/*
* Decrement reference count on an
* inode due to the removal of a
* referencing file structure.
* On the last closei, switchout
* to the close entry point of special
* device handler.
* Note that the handler gets called
* on every open and only on the last
* close.
*/
closei(ip, rw)
int *ip;
{
register *rip;
register dev, maj;
rip = ip;
dev = rip->i_addr[0];
maj = rip->i_addr[0].d_major;
if(rip->i_count <= 1)
switch(rip->i_mode&IFMT) {
case IFCHR:
(*cdevsw[maj].d_close)(dev, rw);
break;
case IFBLK:
(*bdevsw[maj].d_close)(dev, rw);
}
iput(rip);
}
/*
* openi called to allow handler
* of special files to initialize and
* validate before actual IO.
* Called on all sorts of opens
* and also on mount.
*/
openi(ip, rw)
int *ip;
{
register *rip;
register dev, maj;
rip = ip;
dev = rip->i_addr[0];
maj = rip->i_addr[0].d_major;
switch(rip->i_mode&IFMT) {
case IFCHR:
if(maj >= nchrdev)
goto bad;
(*cdevsw[maj].d_open)(dev, rw);
break;
case IFBLK:
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 except for EXEC where
* at least one of the EXEC bits must
* be on.
*/
access(aip, mode)
int *aip;
{
register *ip, m;
ip = aip;
m = mode;
if(m == IWRITE) {
if(getfs(ip->i_dev)->s_ronly != 0) {
u.u_error = EROFS;
return(1);
}
if(ip->i_flag & ITEXT) {
u.u_error = ETXTBSY;
return(1);
}
}
if(u.u_uid == 0) {
if(m == IEXEC && (ip->i_mode &
(IEXEC | (IEXEC>>3) | (IEXEC>>6))) == 0)
goto bad;
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);
bad:
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.
*/
owner()
{
register struct inode *ip;
extern uchar();
if ((ip = namei(uchar, 0)) == 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)
return(1);
u.u_error = EPERM;
return(0);
}
/*
* Allocate a user file descriptor.
*/
ufalloc()
{
register i;
for (i=0; i<NOFILE; i++)
if (u.u_ofile[i] == NULL) {
u.u_ar0[R0] = i;
return(i);
}
u.u_error = EMFILE;
return(-1);
}
/*
* Allocate a user file descriptor
* and a file structure.
* Initialize the descriptor
* to point at the file structure.
*
* no file -- if there are no available
* file structures.
*/
falloc()
{
register struct file *fp;
register i;
if ((i = ufalloc()) < 0)
return(NULL);
for (fp = &file[0]; fp < &file[NFILE]; fp++)
if (fp->f_count==0) {
u.u_ofile[i] = fp;
fp->f_count++;
fp->f_offset[0] = 0;
fp->f_offset[1] = 0;
return(fp);
}
printf("no file\n");
u.u_error = ENFILE;
return(NULL);
}
+234
View File
@@ -0,0 +1,234 @@
#
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../inode.h"
#include "../filsys.h"
#include "../conf.h"
#include "../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"
*/
iget(dev, ino)
{
register struct inode *p;
register *ip2;
int *ip1;
register struct mount *ip;
loop:
ip = NULL;
for(p = &inode[0]; p < &inode[NINODE]; p++) {
if(dev==p->i_dev && ino==p->i_number) {
if((p->i_flag&ILOCK) != 0) {
p->i_flag =| IWANT;
sleep(p, PINOD);
goto loop;
}
if((p->i_flag&IMOUNT) != 0) {
for(ip = &mount[0]; ip < &mount[NMOUNT]; ip++)
if(ip->m_inodp == p) {
dev = ip->m_dev;
ino = ROOTINO;
goto loop;
}
panic("no imt");
}
p->i_count++;
p->i_flag =| ILOCK;
return(p);
}
if(ip==NULL && p->i_count==0)
ip = p;
}
if((p=ip) == NULL) {
printf("Inode table overflow\n");
u.u_error = ENFILE;
return(NULL);
}
p->i_dev = dev;
p->i_number = ino;
p->i_flag = ILOCK;
p->i_count++;
p->i_lastr = -1;
ip = bread(dev, ldiv(ino+31,16));
/*
* Check I/O errors
*/
if (ip->b_flags&B_ERROR) {
brelse(ip);
iput(p);
return(NULL);
}
ip1 = ip->b_addr + 32*lrem(ino+31, 16);
ip2 = &p->i_mode;
while(ip2 < &p->i_addr[8])
*ip2++ = *ip1++;
brelse(ip);
return(p);
}
/*
* Decrement reference count of
* an inode structure.
* On the last reference,
* write the inode out and if necessary,
* truncate and deallocate the file.
*/
iput(p)
struct inode *p;
{
register *rp;
rp = p;
if(rp->i_count == 1) {
rp->i_flag =| ILOCK;
if(rp->i_nlink <= 0) {
itrunc(rp);
rp->i_mode = 0;
ifree(rp->i_dev, rp->i_number);
}
iupdat(rp, time);
prele(rp);
rp->i_flag = 0;
rp->i_number = 0;
}
rp->i_count--;
prele(rp);
}
/*
* Check accessed and update flags on
* an inode structure.
* If either is on, update the inode
* with the corresponding dates
* set to the argument tm.
*/
iupdat(p, tm)
int *p;
int *tm;
{
register *ip1, *ip2, *rp;
int *bp, i;
rp = p;
if((rp->i_flag&(IUPD|IACC)) != 0) {
if(getfs(rp->i_dev)->s_ronly)
return;
i = rp->i_number+31;
bp = bread(rp->i_dev, ldiv(i,16));
ip1 = bp->b_addr + 32*lrem(i, 16);
ip2 = &rp->i_mode;
while(ip2 < &rp->i_addr[8])
*ip1++ = *ip2++;
if(rp->i_flag&IACC) {
*ip1++ = time[0];
*ip1++ = time[1];
} else
ip1 =+ 2;
if(rp->i_flag&IUPD) {
*ip1++ = *tm++;
*ip1++ = *tm;
}
bwrite(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)
int *ip;
{
register *rp, *bp, *cp;
int *dp, *ep;
rp = ip;
if((rp->i_mode&(IFCHR&IFBLK)) != 0)
return;
for(ip = &rp->i_addr[7]; ip >= &rp->i_addr[0]; ip--)
if(*ip) {
if((rp->i_mode&ILARG) != 0) {
bp = bread(rp->i_dev, *ip);
for(cp = bp->b_addr+512; cp >= bp->b_addr; cp--)
if(*cp) {
if(ip == &rp->i_addr[7]) {
dp = bread(rp->i_dev, *cp);
for(ep = dp->b_addr+512; ep >= dp->b_addr; ep--)
if(*ep)
free(rp->i_dev, *ep);
brelse(dp);
}
free(rp->i_dev, *cp);
}
brelse(bp);
}
free(rp->i_dev, *ip);
*ip = 0;
}
rp->i_mode =& ~ILARG;
rp->i_size0 = 0;
rp->i_size1 = 0;
rp->i_flag =| IUPD;
}
/*
* Make a new file.
*/
maknode(mode)
{
register *ip;
ip = ialloc(u.u_pdir->i_dev);
if (ip==NULL)
return(NULL);
ip->i_flag =| IACC|IUPD;
ip->i_mode = mode|IALLOC;
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)
int *ip;
{
register char *cp1, *cp2;
u.u_dent.u_ino = ip->i_number;
cp1 = &u.u_dent.u_name[0];
for(cp2 = &u.u_dbuf[0]; cp2 < &u.u_dbuf[DIRSIZ];)
*cp1++ = *cp2++;
u.u_count = DIRSIZ+2;
u.u_segflg = 1;
u.u_base = &u.u_dent;
writei(u.u_pdir);
iput(u.u_pdir);
}
+266
View File
@@ -0,0 +1,266 @@
#
#include "../param.h"
#include "../user.h"
#include "../systm.h"
#include "../proc.h"
#include "../text.h"
#include "../inode.h"
#include "../seg.h"
#define CLOCK1 0177546
#define CLOCK2 0172540
/*
* Icode is the octal bootstrap
* program executed in user mode
* to bring up the system.
*/
int icode[]
{
0104413, /* sys exec; init; initp */
0000014,
0000010,
0000777, /* br . */
0000014, /* initp: init; 0 */
0000000,
0062457, /* init: </etc/init\0> */
0061564,
0064457,
0064556,
0000164,
};
/*
* Initialization code.
* Called from m40.s or m45.s as
* soon as a stack and segmentation
* have been established.
* Functions:
* clear and free user core
* find which clock is configured
* hand craft 0th process
* call all initialization routines
* fork - process 0 to schedule
* - process 1 execute bootstrap
*
* panic: no clock -- neither clock responds
* loop at loc 6 in user mode -- /etc/init
* cannot be executed.
*/
main()
{
extern schar;
register i, *p;
/*
* zero and free all of core
*/
updlock = 0;
i = *ka6 + USIZE;
UISD->r[0] = 077406;
for(;;) {
UISA->r[0] = i;
if(fuibyte(0) < 0)
break;
clearseg(i);
maxmem++;
mfree(coremap, 1, i);
i++;
}
if(cputype == 70)
for(i=0; i<62; i=+2) {
UBMAP->r[i] = i<<12;
UBMAP->r[i+1] = 0;
}
printf("mem = %l\n", maxmem*5/16);
maxmem = min(maxmem, MAXMEM);
mfree(swapmap, nswap, swplo);
/*
* determine clock
*/
UISA->r[7] = ka6[1]; /* io segment */
UISD->r[7] = 077406;
lks = CLOCK1;
if(fuiword(lks) == -1) {
lks = CLOCK2;
if(fuiword(lks) == -1)
panic("no clock");
}
/*
* set up system process
*/
proc[0].p_addr = *ka6;
proc[0].p_size = USIZE;
proc[0].p_stat = SRUN;
proc[0].p_flag =| SLOAD|SSYS;
u.u_procp = &proc[0];
/*
* set up 'known' i-nodes
*/
*lks = 0115;
cinit();
binit();
iinit();
rootdir = iget(rootdev, ROOTINO);
rootdir->i_flag =& ~ILOCK;
u.u_cdir = iget(rootdev, ROOTINO);
u.u_cdir->i_flag =& ~ILOCK;
/*
* make init process
* enter scheduling loop
* with system process
*/
if(newproc()) {
expand(USIZE+1);
estabur(0, 1, 0, 0);
copyout(icode, 0, sizeof icode);
/*
* Return goes to loc. 0 of user init
* code just copied out.
*/
return;
}
sched();
}
/*
* Load the user hardware segmentation
* registers from the software prototype.
* The software registers must have
* been setup prior by estabur.
*/
sureg()
{
register *up, *rp, a;
a = u.u_procp->p_addr;
up = &u.u_uisa[16];
rp = &UISA->r[16];
if(cputype == 40) {
up =- 8;
rp =- 8;
}
while(rp > &UISA->r[0])
*--rp = *--up + a;
if((up=u.u_procp->p_textp) != NULL)
a =- up->x_caddr;
up = &u.u_uisd[16];
rp = &UISD->r[16];
if(cputype == 40) {
up =- 8;
rp =- 8;
}
while(rp > &UISD->r[0]) {
*--rp = *--up;
if((*rp & WO) == 0)
rp[(UISA-UISD)/2] =- a;
}
}
/*
* 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.
*/
estabur(nt, nd, ns, sep)
{
register a, *ap, *dp;
if(sep) {
if(cputype == 40)
goto err;
if(nseg(nt) > 8 || nseg(nd)+nseg(ns) > 8)
goto err;
} else
if(nseg(nt)+nseg(nd)+nseg(ns) > 8)
goto err;
if(nt+nd+ns+USIZE > maxmem)
goto err;
a = 0;
ap = &u.u_uisa[0];
dp = &u.u_uisd[0];
while(nt >= 128) {
*dp++ = (127<<8) | RO;
*ap++ = a;
a =+ 128;
nt =- 128;
}
if(nt) {
*dp++ = ((nt-1)<<8) | RO;
*ap++ = a;
}
if(sep)
while(ap < &u.u_uisa[8]) {
*ap++ = 0;
*dp++ = 0;
}
a = USIZE;
while(nd >= 128) {
*dp++ = (127<<8) | RW;
*ap++ = a;
a =+ 128;
nd =- 128;
}
if(nd) {
*dp++ = ((nd-1)<<8) | RW;
*ap++ = a;
a =+ nd;
}
while(ap < &u.u_uisa[8]) {
*dp++ = 0;
*ap++ = 0;
}
if(sep)
while(ap < &u.u_uisa[16]) {
*dp++ = 0;
*ap++ = 0;
}
a =+ ns;
while(ns >= 128) {
a =- 128;
ns =- 128;
*--dp = (127<<8) | RW;
*--ap = a;
}
if(ns) {
*--dp = ((128-ns)<<8) | RW | ED;
*--ap = a-128;
}
if(!sep) {
ap = &u.u_uisa[0];
dp = &u.u_uisa[8];
while(ap < &u.u_uisa[8])
*dp++ = *ap++;
ap = &u.u_uisd[0];
dp = &u.u_uisd[8];
while(ap < &u.u_uisd[8])
*dp++ = *ap++;
}
sureg();
return(0);
err:
u.u_error = ENOMEM;
return(-1);
}
/*
* Return the arg/128 rounded up.
*/
nseg(n)
{
return((n+127)>>7);
}
+87
View File
@@ -0,0 +1,87 @@
#
/*
*/
/*
* Structure of the coremap and swapmap
* arrays. Consists of non-zero count
* and base address of that many
* contiguous units.
* (The coremap unit is 64 bytes,
* the swapmap unit is 512 bytes)
* The addresses are increasing and
* the list is terminated with the
* first zero count.
*/
struct map
{
char *m_size;
char *m_addr;
};
/*
* Allocate size units from the given
* map. Return the base of the allocated
* space.
* Algorithm is first fit.
*/
malloc(mp, size)
struct map *mp;
{
register 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, aa)
struct map *mp;
{
register struct map *bp;
register int t;
register int a;
a = aa;
for (bp = mp; 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);
}
}
+200
View File
@@ -0,0 +1,200 @@
#
#include "../param.h"
#include "../inode.h"
#include "../user.h"
#include "../systm.h"
#include "../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
*/
namei(func, flag)
int (*func)();
{
register struct inode *dp;
register c;
register char *cp;
int eo, *bp;
/*
* If name starts with '/' start from
* root; otherwise start from current dir.
*/
dp = u.u_cdir;
if((c=(*func)()) == '/')
dp = rootdir;
iget(dp->i_dev, dp->i_number);
while(c == '/')
c = (*func)();
if(c == '\0' && flag != 0) {
u.u_error = ENOENT;
goto out;
}
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,
* dp must be a directory and
* must have x permission.
*/
if((dp->i_mode&IFMT) != IFDIR) {
u.u_error = ENOTDIR;
goto out;
}
if(access(dp, IEXEC))
goto out;
/*
* 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)();
if(u.u_error)
goto out;
/*
* Set up to search a directory.
*/
u.u_offset[1] = 0;
u.u_offset[0] = 0;
u.u_segflg = 1;
eo = 0;
u.u_count = ldiv(dp->i_size1, DIRSIZ+2);
bp = NULL;
eloop:
/*
* If at the end of the directory,
* the search failed. Report what
* is appropriate as per flag.
*/
if(u.u_count == 0) {
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[1] = eo-DIRSIZ-2; else
dp->i_flag =| IUPD;
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[1]&0777) == 0) {
if(bp != NULL)
brelse(bp);
bp = bread(dp->i_dev,
bmap(dp, ldiv(u.u_offset[1], 512)));
}
/*
* 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_addr+(u.u_offset[1]&0777), &u.u_dent, (DIRSIZ+2)/2);
u.u_offset[1] =+ DIRSIZ+2;
u.u_count--;
if(u.u_dent.u_ino == 0) {
if(eo == 0)
eo = u.u_offset[1];
goto eloop;
}
for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)
if(*cp != cp[u.u_dent.u_name - u.u_dbuf])
goto eloop;
/*
* Here a component matched in a directory.
* If there is more pathname, go back to
* cloop, otherwise return.
*/
if(bp != NULL)
brelse(bp);
if(flag==2 && c=='\0') {
if(access(dp, IWRITE))
goto out;
return(dp);
}
bp = dp->i_dev;
iput(dp);
dp = iget(bp, u.u_dent.u_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);
}
+222
View File
@@ -0,0 +1,222 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../inode.h"
#include "../file.h"
#include "../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 4096,
* pipes will be implemented in LARG
* 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 *ip, *rf, *wf;
int r;
ip = ialloc(rootdev);
if(ip == NULL)
return;
rf = falloc();
if(rf == NULL) {
iput(ip);
return;
}
r = u.u_ar0[R0];
wf = falloc();
if(wf == NULL) {
rf->f_count = 0;
u.u_ofile[r] = NULL;
iput(ip);
return;
}
u.u_ar0[R1] = u.u_ar0[R0];
u.u_ar0[R0] = 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_flag = IACC|IUPD;
ip->i_mode = IALLOC;
}
/*
* Read call directed to a pipe.
*/
readp(fp)
int *fp;
{
register *rp, *ip;
rp = fp;
ip = rp->f_inode;
loop:
/*
* Very conservative locking.
*/
plock(ip);
/*
* If the head (read) has caught up with
* the tail (write), reset both to 0.
*/
if(rp->f_offset[1] == ip->i_size1) {
if(rp->f_offset[1] != 0) {
rp->f_offset[1] = 0;
ip->i_size1 = 0;
if(ip->i_mode&IWRITE) {
ip->i_mode =& ~IWRITE;
wakeup(ip+1);
}
}
/*
* 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(ip+2, PPIPE);
goto loop;
}
/*
* Read and return
*/
u.u_offset[0] = 0;
u.u_offset[1] = rp->f_offset[1];
readi(ip);
rp->f_offset[1] = u.u_offset[1];
prele(ip);
}
/*
* Write call directed to a pipe.
*/
writep(fp)
{
register *rp, *ip, c;
rp = fp;
ip = rp->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_size1 == PIPSIZ) {
ip->i_mode =| IWRITE;
prele(ip);
sleep(ip+1, PPIPE);
goto loop;
}
/*
* Write what is possible and
* loop back.
*/
u.u_offset[0] = 0;
u.u_offset[1] = ip->i_size1;
u.u_count = min(c, PIPSIZ-u.u_offset[1]);
c =- u.u_count;
writei(ip);
prele(ip);
if(ip->i_mode&IREAD) {
ip->i_mode =& ~IREAD;
wakeup(ip+2);
}
goto loop;
}
/*
* Lock a pipe.
* If its already locked,
* set the WANT bit and sleep.
*/
plock(ip)
int *ip;
{
register *rp;
rp = ip;
while(rp->i_flag&ILOCK) {
rp->i_flag =| IWANT;
sleep(rp, PPIPE);
}
rp->i_flag =| ILOCK;
}
/*
* Unlock a pipe.
* If WANT bit is on,
* wakeup.
* This routine is also used
* to unlock inodes in general.
*/
prele(ip)
int *ip;
{
register *rp;
rp = ip;
rp->i_flag =& ~ILOCK;
if(rp->i_flag&IWANT) {
rp->i_flag =& ~IWANT;
wakeup(rp);
}
}
+150
View File
@@ -0,0 +1,150 @@
#
/*
*/
#include "../param.h"
#include "../seg.h"
#include "../buf.h"
#include "../conf.h"
/*
* Address and structure of the
* KL-11 console device registers.
*/
struct
{
int rsr;
int rbr;
int xsr;
int xbr;
};
/*
* In case console is off,
* panicstr contains argument to last
* call to panic.
*/
char *panicstr;
/*
* Scaled down version of C Library printf.
* Only %s %l %d (==%l) %o 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.
*/
printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc)
char fmt[];
{
register char *s;
register *adx, c;
adx = &x1;
loop:
while((c = *fmt++) != '%') {
if(c == '\0')
return;
putchar(c);
}
c = *fmt++;
if(c == 'd' || c == 'l' || c == 'o')
printn(*adx, c=='o'? 8: 10);
if(c == 's') {
s = *adx;
while(c = *s++)
putchar(c);
}
adx++;
goto loop;
}
/*
* Print an unsigned integer in base b.
*/
printn(n, b)
{
register a;
if(a = ldiv(n, b))
printn(a, b);
putchar(lrem(n, b) + '0');
}
/*
* Print a character on console.
* Attempts to save and restore device
* status.
* If the switches are 0, all
* printing is inhibited.
*/
putchar(c)
{
register rc, s;
rc = c;
if(SW->integ == 0)
return;
while((KL->xsr&0200) == 0)
;
if(rc == 0)
return;
s = KL->xsr;
KL->xsr = 0;
KL->xbr = rc;
if(rc == '\n') {
putchar('\r');
putchar(0177);
putchar(0177);
}
putchar(0);
KL->xsr = s;
}
/*
* 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)
{
printf("%s on dev %l/%l\n", str, dev.d_major, dev.d_minor);
}
/*
* 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)
int *bp;
{
register *rbp;
rbp = bp;
prdev("err", rbp->b_dev);
printf("bn%l er%o %o\n", rbp->b_blkno, o1, o2);
}
+195
View File
@@ -0,0 +1,195 @@
#
/*
*/
#include "../param.h"
#include "../inode.h"
#include "../user.h"
#include "../buf.h"
#include "../conf.h"
#include "../systm.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
*/
readi(aip)
struct inode *aip;
{
int *bp;
int lbn, bn, on;
register dn, n;
register struct inode *ip;
ip = aip;
if(u.u_count == 0)
return;
ip->i_flag =| IACC;
if((ip->i_mode&IFMT) == IFCHR) {
(*cdevsw[ip->i_addr[0].d_major].d_read)(ip->i_addr[0]);
return;
}
do {
lbn = bn = lshift(u.u_offset, -9);
on = u.u_offset[1] & 0777;
n = min(512-on, u.u_count);
if((ip->i_mode&IFMT) != IFBLK) {
dn = dpcmp(ip->i_size0&0377, ip->i_size1,
u.u_offset[0], u.u_offset[1]);
if(dn <= 0)
return;
n = min(n, dn);
if ((bn = bmap(ip, lbn)) == 0)
return;
dn = ip->i_dev;
} else {
dn = ip->i_addr[0];
rablock = bn+1;
}
if (ip->i_lastr+1 == lbn)
bp = breada(dn, bn, rablock);
else
bp = bread(dn, bn);
ip->i_lastr = lbn;
iomove(bp, on, n, B_READ);
brelse(bp);
} while(u.u_error==0 && u.u_count!=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
*/
writei(aip)
struct inode *aip;
{
int *bp;
int n, on;
register dn, bn;
register struct inode *ip;
ip = aip;
ip->i_flag =| IACC|IUPD;
if((ip->i_mode&IFMT) == IFCHR) {
(*cdevsw[ip->i_addr[0].d_major].d_write)(ip->i_addr[0]);
return;
}
if (u.u_count == 0)
return;
do {
bn = lshift(u.u_offset, -9);
on = u.u_offset[1] & 0777;
n = min(512-on, u.u_count);
if((ip->i_mode&IFMT) != IFBLK) {
if ((bn = bmap(ip, bn)) == 0)
return;
dn = ip->i_dev;
} else
dn = ip->i_addr[0];
if(n == 512)
bp = getblk(dn, bn); else
bp = bread(dn, bn);
iomove(bp, on, n, B_WRITE);
if(u.u_error != 0)
brelse(bp); else
if ((u.u_offset[1]&0777)==0)
bawrite(bp); else
bdwrite(bp);
if(dpcmp(ip->i_size0&0377, ip->i_size1,
u.u_offset[0], u.u_offset[1]) < 0 &&
(ip->i_mode&(IFBLK&IFCHR)) == 0) {
ip->i_size0 = u.u_offset[0];
ip->i_size1 = u.u_offset[1];
}
ip->i_flag =| IUPD;
} while(u.u_error==0 && u.u_count!=0);
}
/*
* Return the logical maximum
* of the 2 arguments.
*/
max(a, b)
char *a, *b;
{
if(a > b)
return(a);
return(b);
}
/*
* Return the logical minimum
* of the 2 arguments.
*/
min(a, b)
char *a, *b;
{
if(a < b)
return(a);
return(b);
}
/*
* Move 'an' bytes at byte location
* &bp->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.
*
* There are 2 algorithms,
* if source address, dest address and count
* are all even in a user copy,
* then the machine language copyin/copyout
* is called.
* If not, its done byte-by-byte with
* cpass and passc.
*/
iomove(bp, o, an, flag)
struct buf *bp;
{
register char *cp;
register int n, t;
n = an;
cp = bp->b_addr + o;
if(u.u_segflg==0 && ((n | cp | u.u_base)&01)==0) {
if (flag==B_WRITE)
cp = copyin(u.u_base, cp, n);
else
cp = copyout(cp, u.u_base, n);
if (cp) {
u.u_error = EFAULT;
return;
}
u.u_base =+ n;
dpadd(u.u_offset, n);
u.u_count =- n;
return;
}
if (flag==B_WRITE) {
while(n--) {
if ((t = cpass()) < 0)
return;
*cp++ = t;
}
} else
while (n--)
if(passc(*cp++) < 0)
return;
}
+374
View File
@@ -0,0 +1,374 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../proc.h"
#include "../inode.h"
#include "../reg.h"
/*
* Priority for tracing
*/
#define IPCPRI (-1)
/*
* Structure to access an array of integers.
*/
struct
{
int inta[];
};
/*
* Tracing variables.
* Used to pass trace command from
* parent to child being traced.
* This data base cannot be
* shared and is locked
* per user.
*/
struct
{
int ip_lock;
int ip_req;
int ip_addr;
int ip_data;
} ipc;
/*
* Send the specified signal to
* all processes with 'tp' as its
* controlling teletype.
* Called by tty.c for quits and
* interrupts.
*/
signal(tp, sig)
{
register struct proc *p;
for(p = &proc[0]; p < &proc[NPROC]; p++)
if(p->p_ttyp == tp)
psignal(p, sig);
}
/*
* Send the specified signal to
* the specified process.
*/
psignal(p, sig)
int *p;
{
register *rp;
if(sig >= NSIG)
return;
rp = p;
if(rp->p_sig != SIGKIL)
rp->p_sig = sig;
if(rp->p_stat > PUSER)
rp->p_stat = PUSER;
if(rp->p_stat == SWAIT)
setrun(rp);
}
/*
* Returns true if the current
* process has a signal to process.
* This is asked at least once
* each time a process enters the
* system.
* A signal does not do anything
* directly to a process; it sets
* a flag that asks the process to
* do something to itself.
*/
issig()
{
register n;
register struct proc *p;
p = u.u_procp;
if(n = p->p_sig) {
if (p->p_flag&STRC) {
stop();
if ((n = p->p_sig) == 0)
return(0);
}
if((u.u_signal[n]&1) == 0)
return(n);
}
return(0);
}
/*
* Enter the tracing STOP state.
* In this state, the parent is
* informed and the process is able to
* receive commands from the parent.
*/
stop()
{
register struct proc *pp, *cp;
loop:
cp = u.u_procp;
if(cp->p_ppid != 1)
for (pp = &proc[0]; pp < &proc[NPROC]; pp++)
if (pp->p_pid == cp->p_ppid) {
wakeup(pp);
cp->p_stat = SSTOP;
swtch();
if ((cp->p_flag&STRC)==0 || procxmt())
return;
goto loop;
}
exit();
}
/*
* Perform the action specified by
* the current signal.
* The usual sequence is:
* if(issig())
* psig();
*/
psig()
{
register n, p;
register *rp;
rp = u.u_procp;
n = rp->p_sig;
rp->p_sig = 0;
if((p=u.u_signal[n]) != 0) {
u.u_error = 0;
if(n != SIGINS && n != SIGTRC)
u.u_signal[n] = 0;
n = u.u_ar0[R6] - 4;
grow(n);
suword(n+2, u.u_ar0[RPS]);
suword(n, u.u_ar0[R7]);
u.u_ar0[R6] = n;
u.u_ar0[RPS] =& ~TBIT;
u.u_ar0[R7] = p;
return;
}
switch(n) {
case SIGQIT:
case SIGINS:
case SIGTRC:
case SIGIOT:
case SIGEMT:
case SIGFPT:
case SIGBUS:
case SIGSEG:
case SIGSYS:
u.u_arg[0] = n;
if(core())
n =+ 0200;
}
u.u_arg[0] = (u.u_ar0[R0]<<8) | n;
exit();
}
/*
* Create a core image on the file "core"
* If you are looking for protection glitches,
* there are probably a wealth of them here
* when this occurs to a suid command.
*
* It writes USIZE block of the
* user.h area followed by the entire
* data+stack segments.
*/
core()
{
register s, *ip;
extern schar;
u.u_error = 0;
u.u_dirp = "core";
ip = namei(&schar, 1);
if(ip == NULL) {
if(u.u_error)
return(0);
ip = maknode(0666);
if(ip == NULL)
return(0);
}
if(!access(ip, IWRITE) &&
(ip->i_mode&IFMT) == 0 &&
u.u_uid == u.u_ruid) {
itrunc(ip);
u.u_offset[0] = 0;
u.u_offset[1] = 0;
u.u_base = &u;
u.u_count = USIZE*64;
u.u_segflg = 1;
writei(ip);
s = u.u_procp->p_size - USIZE;
estabur(0, s, 0, 0);
u.u_base = 0;
u.u_count = s*64;
u.u_segflg = 0;
writei(ip);
}
iput(ip);
return(u.u_error==0);
}
/*
* grow the stack to include the SP
* true return if successful.
*/
grow(sp)
char *sp;
{
register a, si, i;
if(sp >= -u.u_ssize*64)
return(0);
si = ldiv(-sp, 64) - u.u_ssize + SINCR;
if(si <= 0)
return(0);
if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep))
return(0);
expand(u.u_procp->p_size+si);
a = u.u_procp->p_addr + u.u_procp->p_size;
for(i=u.u_ssize; i; i--) {
a--;
copyseg(a-si, a);
}
for(i=si; i; i--)
clearseg(--a);
u.u_ssize =+ si;
return(1);
}
/*
* sys-trace system call.
*/
ptrace()
{
register struct proc *p;
if (u.u_arg[2] <= 0) {
u.u_procp->p_flag =| STRC;
return;
}
for (p=proc; p < &proc[NPROC]; p++)
if (p->p_stat==SSTOP
&& p->p_pid==u.u_arg[0]
&& p->p_ppid==u.u_procp->p_pid)
goto found;
u.u_error = ESRCH;
return;
found:
while (ipc.ip_lock)
sleep(&ipc, IPCPRI);
ipc.ip_lock = p->p_pid;
ipc.ip_data = u.u_ar0[R0];
ipc.ip_addr = u.u_arg[1] & ~01;
ipc.ip_req = u.u_arg[2];
p->p_flag =& ~SWTED;
setrun(p);
while (ipc.ip_req > 0)
sleep(&ipc, IPCPRI);
u.u_ar0[R0] = ipc.ip_data;
if (ipc.ip_req < 0)
u.u_error = EIO;
ipc.ip_lock = 0;
wakeup(&ipc);
}
/*
* Code that the child process
* executes to implement the command
* of the parent process in tracing.
*/
procxmt()
{
register int i;
register int *p;
if (ipc.ip_lock != u.u_procp->p_pid)
return(0);
i = ipc.ip_req;
ipc.ip_req = 0;
wakeup(&ipc);
switch (i) {
/* read user I */
case 1:
if (fuibyte(ipc.ip_addr) == -1)
goto error;
ipc.ip_data = fuiword(ipc.ip_addr);
break;
/* read user D */
case 2:
if (fubyte(ipc.ip_addr) == -1)
goto error;
ipc.ip_data = fuword(ipc.ip_addr);
break;
/* read u */
case 3:
i = ipc.ip_addr;
if (i<0 || i >= (USIZE<<6))
goto error;
ipc.ip_data = u.inta[i>>1];
break;
/* write user I (for now, always an error) */
case 4:
if (suiword(ipc.ip_addr, 0) < 0)
goto error;
suiword(ipc.ip_addr, ipc.ip_data);
break;
/* write user D */
case 5:
if (suword(ipc.ip_addr, 0) < 0)
goto error;
suword(ipc.ip_addr, ipc.ip_data);
break;
/* write u */
case 6:
p = &u.inta[ipc.ip_addr>>1];
if (p >= u.u_fsav && p < &u.u_fsav[25])
goto ok;
for (i=0; i<9; i++)
if (p == &u.u_ar0[regloc[i]])
goto ok;
goto error;
ok:
if (p == &u.u_ar0[RPS]) {
ipc.ip_data =| 0170000; /* assure user space */
ipc.ip_data =& ~0340; /* priority 0 */
}
*p = ipc.ip_data;
break;
/* set signal and continue */
case 7:
u.u_procp->p_sig = ipc.ip_data;
return(1);
/* force exit */
case 8:
exit();
default:
error:
ipc.ip_req = -1;
}
return(0);
}
+490
View File
@@ -0,0 +1,490 @@
#
/*
*/
#include "../param.h"
#include "../user.h"
#include "../proc.h"
#include "../text.h"
#include "../systm.h"
#include "../file.h"
#include "../inode.h"
#include "../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<0 a signal cannot disturb the sleep;
* if pri>=0 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)
{
register *rp, s;
s = PS->integ;
rp = u.u_procp;
if(pri >= 0) {
if(issig())
goto psig;
spl6();
rp->p_wchan = chan;
rp->p_stat = SWAIT;
rp->p_pri = pri;
spl0();
if(runin != 0) {
runin = 0;
wakeup(&runin);
}
swtch();
if(issig())
goto psig;
} else {
spl6();
rp->p_wchan = chan;
rp->p_stat = SSLEEP;
rp->p_pri = pri;
spl0();
swtch();
}
PS->integ = s;
return;
/*
* If priority was low (>=0) and
* there has been a signal,
* execute non-local goto to
* the qsav location.
* (see trap1/trap.c)
*/
psig:
aretu(u.u_qsav);
}
/*
* Wake up all processes sleeping on chan.
*/
wakeup(chan)
{
register struct proc *p;
register c, i;
c = chan;
p = &proc[0];
i = NPROC;
do {
if(p->p_wchan == c) {
setrun(p);
}
p++;
} while(--i);
}
/*
* Set the process running;
* arrange for it to be swapped in if necessary.
*/
setrun(p)
{
register struct proc *rp;
rp = p;
rp->p_wchan = 0;
rp->p_stat = SRUN;
if(rp->p_pri < curpri)
runrun++;
if(runout != 0 && (rp->p_flag&SLOAD) == 0) {
runout = 0;
wakeup(&runout);
}
}
/*
* Set user priority.
* The rescheduling flag (runrun)
* is set if the priority is higher
* than the currently running process.
*/
setpri(up)
{
register *pp, p;
pp = up;
p = (pp->p_cpu & 0377)/16;
p =+ PUSER + pp->p_nice;
if(p > 127)
p = 127;
if(p > curpri)
runrun++;
pp->p_pri = 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.
* Although it is not remarkably evident, the basic
* synchronization here is on the runin flag, which is
* slept on and is set once per second by the clock routine.
* Core shuffling therefore takes place once per second.
*
* panic: swap error -- IO error while swapping.
* this is the one panic that should be
* handled in a less drastic way. Its
* very hard.
*/
sched()
{
struct proc *p1;
register struct proc *rp;
register a, n;
/*
* find user to swap in
* of users ready, select one out longest
*/
goto loop;
sloop:
runin++;
sleep(&runin, PSWP);
loop:
spl6();
n = -1;
for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
rp->p_time > n) {
p1 = rp;
n = rp->p_time;
}
if(n == -1) {
runout++;
sleep(&runout, PSWP);
goto loop;
}
/*
* see if there is core for that process
*/
spl0();
rp = p1;
a = rp->p_size;
if((rp=rp->p_textp) != NULL)
if(rp->x_ccount == 0)
a =+ rp->x_size;
if((a=malloc(coremap, a)) != NULL)
goto found2;
/*
* none found,
* look around for easy core
*/
spl6();
for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD &&
(rp->p_stat == SWAIT || rp->p_stat==SSTOP))
goto found1;
/*
* no easy core,
* if this process is deserving,
* look around for
* oldest process in core
*/
if(n < 3)
goto sloop;
n = -1;
for(rp = &proc[0]; rp < &proc[NPROC]; rp++)
if((rp->p_flag&(SSYS|SLOCK|SLOAD))==SLOAD &&
(rp->p_stat==SRUN || rp->p_stat==SSLEEP) &&
rp->p_time > n) {
p1 = rp;
n = rp->p_time;
}
if(n < 2)
goto sloop;
rp = p1;
/*
* swap user out
*/
found1:
spl0();
rp->p_flag =& ~SLOAD;
xswap(rp, 1, 0);
goto loop;
/*
* swap user in
*/
found2:
if((rp=p1->p_textp) != NULL) {
if(rp->x_ccount == 0) {
if(swap(rp->x_daddr, a, rp->x_size, B_READ))
goto swaper;
rp->x_caddr = a;
a =+ rp->x_size;
}
rp->x_ccount++;
}
rp = p1;
if(swap(rp->p_addr, a, rp->p_size, B_READ))
goto swaper;
mfree(swapmap, (rp->p_size+7)/8, rp->p_addr);
rp->p_addr = a;
rp->p_flag =| SLOAD;
rp->p_time = 0;
goto loop;
swaper:
panic("swap error");
}
/*
* 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.
*/
swtch()
{
static struct proc *p;
register i, n;
register struct proc *rp;
if(p == NULL)
p = &proc[0];
/*
* Remember stack of caller
*/
savu(u.u_rsav);
/*
* Switch to scheduler's stack
*/
retu(proc[0].p_addr);
loop:
runrun = 0;
rp = p;
p = NULL;
n = 128;
/*
* Search for highest-priority runnable process
*/
i = NPROC;
do {
rp++;
if(rp >= &proc[NPROC])
rp = &proc[0];
if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)!=0) {
if(rp->p_pri < n) {
p = rp;
n = rp->p_pri;
}
}
} while(--i);
/*
* If no process is runnable, idle.
*/
if(p == NULL) {
p = rp;
idle();
goto loop;
}
rp = p;
curpri = n;
/*
* Switch to stack of the new process and set up
* his segmentation registers.
*/
retu(rp->p_addr);
sureg();
/*
* If the new process paused because it was
* swapped out, set the stack level to the last call
* to savu(u_ssav). This means that the return
* which is executed immediately after the call to aretu
* actually returns from the last routine which did
* the savu.
*
* You are not expected to understand this.
*/
if(rp->p_flag&SSWAP) {
rp->p_flag =& ~SSWAP;
aretu(u.u_ssav);
}
/*
* The value returned here has many subtle implications.
* See the newproc comments.
*/
return(1);
}
/*
* Create a new process-- the internal version of
* sys fork.
* It returns 1 in the new process.
* How this happens is rather hard to understand.
* The essential fact is that the new process is created
* in such a way that appears to have started executing
* in the same call to newproc as the parent;
* but in fact the code that runs is that of swtch.
* The subtle implication of the returned value of swtch
* (see above) is that this is the value that newproc's
* caller in the new process sees.
*/
newproc()
{
int a1, a2;
struct proc *p, *up;
register struct proc *rpp;
register *rip, 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 < 0) {
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)
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_flag = SLOAD;
rpp->p_uid = rip->p_uid;
rpp->p_ttyp = rip->p_ttyp;
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;
/*
* make duplicate entries
* where needed
*/
for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)
if((rpp = *rip++) != NULL)
rpp->f_count++;
if((rpp=up->p_textp) != NULL) {
rpp->x_count++;
rpp->x_ccount++;
}
u.u_cdir->i_count++;
/*
* Partially simulate the environment
* of the new process so that when it is actually
* created (by copying) it will look right.
*/
savu(u.u_rsav);
rpp = p;
u.u_procp = rpp;
rip = up;
n = rip->p_size;
a1 = rip->p_addr;
rpp->p_size = n;
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;
savu(u.u_ssav);
xswap(rpp, 0, 0);
rpp->p_flag =| SSWAP;
rip->p_stat = SRUN;
} else {
/*
* There is core, so just copy.
*/
rpp->p_addr = a2;
while(n--)
copyseg(a1++, a2++);
}
u.u_procp = rip;
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.
* Because of the ssave and SSWAP flags, control will
* resume after the swap in swtch, which executes the return
* from this stack level.
*
* After the expansion, the caller will take care of copying
* the user's stack towards or away from the data area.
*/
expand(newsize)
{
int i, n;
register *p, 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;
}
savu(u.u_rsav);
a2 = malloc(coremap, newsize);
if(a2 == NULL) {
savu(u.u_ssav);
xswap(p, 1, n);
p->p_flag =| SSWAP;
swtch();
/* no return */
}
p->p_addr = a2;
for(i=0; i<n; i++)
copyseg(a1+i, a2++);
mfree(coremap, n, a1);
retu(p->p_addr);
sureg();
}
+207
View File
@@ -0,0 +1,207 @@
#
/*
*/
#include "../param.h"
#include "../conf.h"
#include "../inode.h"
#include "../user.h"
#include "../buf.h"
#include "../systm.h"
/*
* Bmap defines the structure of file system storage
* by returning the physical block number on a device given the
* inode and the logical block number in a file.
* When convenient, it also leaves the physical
* block number of the next block of the file in rablock
* for use in read-ahead.
*/
bmap(ip, bn)
struct inode *ip;
int bn;
{
register *bp, *bap, nb;
int *nbp, d, i;
d = ip->i_dev;
if(bn & ~077777) {
u.u_error = EFBIG;
return(0);
}
if((ip->i_mode&ILARG) == 0) {
/*
* small file algorithm
*/
if((bn & ~7) != 0) {
/*
* convert small to large
*/
if ((bp = alloc(d)) == NULL)
return(NULL);
bap = bp->b_addr;
for(i=0; i<8; i++) {
*bap++ = ip->i_addr[i];
ip->i_addr[i] = 0;
}
ip->i_addr[0] = bp->b_blkno;
bdwrite(bp);
ip->i_mode =| ILARG;
goto large;
}
nb = ip->i_addr[bn];
if(nb == 0 && (bp = alloc(d)) != NULL) {
bdwrite(bp);
nb = bp->b_blkno;
ip->i_addr[bn] = nb;
ip->i_flag =| IUPD;
}
rablock = 0;
if (bn<7)
rablock = ip->i_addr[bn+1];
return(nb);
}
/*
* large file algorithm
*/
large:
i = bn>>8;
if(bn & 0174000)
i = 7;
if((nb=ip->i_addr[i]) == 0) {
ip->i_flag =| IUPD;
if ((bp = alloc(d)) == NULL)
return(NULL);
ip->i_addr[i] = bp->b_blkno;
} else
bp = bread(d, nb);
bap = bp->b_addr;
/*
* "huge" fetch of double indirect block
*/
if(i == 7) {
i = ((bn>>8) & 0377) - 7;
if((nb=bap[i]) == 0) {
if((nbp = alloc(d)) == NULL) {
brelse(bp);
return(NULL);
}
bap[i] = nbp->b_blkno;
bdwrite(bp);
} else {
brelse(bp);
nbp = bread(d, nb);
}
bp = nbp;
bap = bp->b_addr;
}
/*
* normal indirect fetch
*/
i = bn & 0377;
if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) {
nb = nbp->b_blkno;
bap[i] = nb;
bdwrite(nbp);
bdwrite(bp);
} else
brelse(bp);
rablock = 0;
if(i < 255)
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)
char c;
{
if(u.u_segflg)
*u.u_base = c; else
if(subyte(u.u_base, c) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
if(++u.u_offset[1] == 0)
u.u_offset[0]++;
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;
if(u.u_count == 0)
return(-1);
if(u.u_segflg)
c = *u.u_base; else
if((c=fubyte(u.u_base)) < 0) {
u.u_error = EFAULT;
return(-1);
}
u.u_count--;
if(++u.u_offset[1] == 0)
u.u_offset[0]++;
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()
{
}
/*
* copy count words from from to to.
*/
bcopy(from, to, count)
int *from, *to;
{
register *a, *b, c;
a = from;
b = to;
c = count;
do
*b++ = *a++;
while(--c);
}
+407
View File
@@ -0,0 +1,407 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../proc.h"
#include "../buf.h"
#include "../reg.h"
#include "../inode.h"
/*
* exec system call.
* Because of the fact that an I/O buffer is used
* to store the caller's arguments during exec,
* and more buffers are needed to read in the text file,
* deadly embraces waiting for free buffers are possible.
* Therefore the number of processes simultaneously
* running in exec has to be limited to NEXEC.
*/
#define EXPRI -1
exec()
{
int ap, na, nc, *bp;
int ts, ds, sep;
register c, *ip;
register char *cp;
extern uchar;
/*
* pick up file names
* and check various modes
* for execute permission
*/
ip = namei(&uchar, 0);
if(ip == NULL)
return;
while(execnt >= NEXEC)
sleep(&execnt, EXPRI);
execnt++;
bp = getblk(NODEV);
if(access(ip, IEXEC) || (ip->i_mode&IFMT)!=0)
goto bad;
/*
* pack up arguments into
* allocated disk buffer
*/
cp = bp->b_addr;
na = 0;
nc = 0;
while(ap = fuword(u.u_arg[1])) {
na++;
if(ap == -1)
goto bad;
u.u_arg[1] =+ 2;
for(;;) {
c = fubyte(ap++);
if(c == -1)
goto bad;
*cp++ = c;
nc++;
if(nc > 510) {
u.u_error = E2BIG;
goto bad;
}
if(c == 0)
break;
}
}
if((nc&1) != 0) {
*cp++ = 0;
nc++;
}
/*
* read in first 8 bytes
* of file for segment
* sizes:
* w0 = 407/410/411 (410 implies RO text) (411 implies sep ID)
* w1 = text size
* w2 = data size
* w3 = bss size
*/
u.u_base = &u.u_arg[0];
u.u_count = 8;
u.u_offset[1] = 0;
u.u_offset[0] = 0;
u.u_segflg = 1;
readi(ip);
u.u_segflg = 0;
if(u.u_error)
goto bad;
sep = 0;
if(u.u_arg[0] == 0407) {
u.u_arg[2] =+ u.u_arg[1];
u.u_arg[1] = 0;
} else
if(u.u_arg[0] == 0411)
sep++; else
if(u.u_arg[0] != 0410) {
u.u_error = ENOEXEC;
goto bad;
}
if(u.u_arg[1]!=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 = ((u.u_arg[1]+63)>>6) & 01777;
ds = ((u.u_arg[2]+u.u_arg[3]+63)>>6) & 01777;
if(estabur(ts, ds, SSIZE, sep))
goto bad;
/*
* allocate and clear core
* at this point, committed
* to the new image
*/
u.u_prof[3] = 0;
xfree();
expand(USIZE);
xalloc(ip);
c = USIZE+ds+SSIZE;
expand(c);
while(--c >= USIZE)
clearseg(u.u_procp->p_addr+c);
/*
* read in data segment
*/
estabur(0, ds, 0, 0);
u.u_base = 0;
u.u_offset[1] = 020+u.u_arg[1];
u.u_count = u.u_arg[2];
readi(ip);
/*
* initialize stack segment
*/
u.u_tsize = ts;
u.u_dsize = ds;
u.u_ssize = SSIZE;
u.u_sep = sep;
estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep);
cp = bp->b_addr;
ap = -nc - na*2 - 4;
u.u_ar0[R6] = ap;
suword(ap, na);
c = -nc;
while(na--) {
suword(ap=+2, c);
do
subyte(c++, *cp);
while(*cp++);
}
suword(ap+2, -1);
/*
* 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;
}
/*
* clear sigs, regs and return
*/
c = ip;
for(ip = &u.u_signal[0]; ip < &u.u_signal[NSIG]; ip++)
if((*ip & 1) == 0)
*ip = 0;
for(cp = &regloc[0]; cp < &regloc[6];)
u.u_ar0[*cp++] = 0;
u.u_ar0[R7] = 0;
for(ip = &u.u_fsav[0]; ip < &u.u_fsav[25];)
*ip++ = 0;
ip = c;
bad:
iput(ip);
brelse(bp);
if(execnt >= NEXEC)
wakeup(&execnt);
execnt--;
}
/*
* exit system call:
* pass back caller's r0
*/
rexit()
{
u.u_arg[0] = u.u_ar0[R0] << 8;
exit();
}
/*
* Release resources.
* Save u. area for parent to look at.
* Enter zombie state.
* Wake up parent and init processes,
* and dispose of children.
*/
exit()
{
register int *q, a;
register struct proc *p;
u.u_procp->p_flag =& ~STRC;
for(q = &u.u_signal[0]; q < &u.u_signal[NSIG];)
*q++ = 1;
for(q = &u.u_ofile[0]; q < &u.u_ofile[NOFILE]; q++)
if(a = *q) {
*q = NULL;
closef(a);
}
iput(u.u_cdir);
xfree();
a = malloc(swapmap, 1);
if(a == NULL)
panic("out of swap");
p = getblk(swapdev, a);
bcopy(&u, p->b_addr, 256);
bwrite(p);
q = u.u_procp;
mfree(coremap, q->p_size, q->p_addr);
q->p_addr = a;
q->p_stat = SZOMB;
loop:
for(p = &proc[0]; p < &proc[NPROC]; p++)
if(q->p_ppid == p->p_pid) {
wakeup(&proc[1]);
wakeup(p);
for(p = &proc[0]; p < &proc[NPROC]; p++)
if(q->p_pid == p->p_ppid) {
p->p_ppid = 1;
if (p->p_stat == SSTOP)
setrun(p);
}
swtch();
/* no return */
}
q->p_ppid = 1;
goto loop;
}
/*
* 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, *bp;
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_ar0[R0] = p->p_pid;
bp = bread(swapdev, f=p->p_addr);
mfree(swapmap, 1, f);
p->p_stat = NULL;
p->p_pid = 0;
p->p_ppid = 0;
p->p_sig = 0;
p->p_ttyp = 0;
p->p_flag = 0;
p = bp->b_addr;
u.u_cstime[0] =+ p->u_cstime[0];
dpadd(u.u_cstime, p->u_cstime[1]);
dpadd(u.u_cstime, p->u_stime);
u.u_cutime[0] =+ p->u_cutime[0];
dpadd(u.u_cutime, p->u_cutime[1]);
dpadd(u.u_cutime, p->u_utime);
u.u_ar0[R1] = p->u_arg[0];
brelse(bp);
return;
}
if(p->p_stat == SSTOP) {
if((p->p_flag&SWTED) == 0) {
p->p_flag =| SWTED;
u.u_ar0[R0] = p->p_pid;
u.u_ar0[R1] = (p->p_sig<<8) | 0177;
return;
}
p->p_flag =& ~(STRC|SWTED);
setrun(p);
}
}
if(f) {
sleep(u.u_procp, PWAIT);
goto loop;
}
u.u_error = ECHILD;
}
/*
* fork system call.
*/
fork()
{
register struct proc *p1, *p2;
p1 = u.u_procp;
for(p2 = &proc[0]; p2 < &proc[NPROC]; p2++)
if(p2->p_stat == NULL)
goto found;
u.u_error = EAGAIN;
goto out;
found:
if(newproc()) {
u.u_ar0[R0] = p1->p_pid;
u.u_cstime[0] = 0;
u.u_cstime[1] = 0;
u.u_stime = 0;
u.u_cutime[0] = 0;
u.u_cutime[1] = 0;
u.u_utime = 0;
return;
}
u.u_ar0[R0] = p2->p_pid;
out:
u.u_ar0[R7] =+ 2;
}
/*
* break system call.
* -- bad planning: "break" is a dirty word in C.
*/
sbreak()
{
register a, n, d;
int i;
/*
* set n to new data size
* set d to new-old
* set n to new total size
*/
n = (((u.u_arg[0]+63)>>6) & 01777);
if(!u.u_sep)
n =- nseg(u.u_tsize) * 128;
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))
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);
}
+289
View File
@@ -0,0 +1,289 @@
#
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../reg.h"
#include "../file.h"
#include "../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 *fp, m;
m = mode;
fp = getf(u.u_ar0[R0]);
if(fp == NULL)
return;
if((fp->f_flag&m) == 0) {
u.u_error = EBADF;
return;
}
u.u_base = u.u_arg[0];
u.u_count = u.u_arg[1];
u.u_segflg = 0;
if(fp->f_flag&FPIPE) {
if(m==FREAD)
readp(fp); else
writep(fp);
} else {
u.u_offset[1] = fp->f_offset[1];
u.u_offset[0] = fp->f_offset[0];
if(m==FREAD)
readi(fp->f_inode); else
writei(fp->f_inode);
dpadd(fp->f_offset, u.u_arg[1]-u.u_count);
}
u.u_ar0[R0] = u.u_arg[1]-u.u_count;
}
/*
* open system call
*/
open()
{
register *ip;
extern uchar;
ip = namei(&uchar, 0);
if(ip == NULL)
return;
u.u_arg[1]++;
open1(ip, u.u_arg[1], 0);
}
/*
* creat system call
*/
creat()
{
register *ip;
extern uchar;
ip = namei(&uchar, 1);
if(ip == NULL) {
if(u.u_error)
return;
ip = maknode(u.u_arg[1]&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)
int *ip;
{
register struct file *fp;
register *rip, m;
int i;
rip = ip;
m = mode;
if(trf != 2) {
if(m&FREAD)
access(rip, IREAD);
if(m&FWRITE) {
access(rip, IWRITE);
if((rip->i_mode&IFMT) == IFDIR)
u.u_error = EISDIR;
}
}
if(u.u_error)
goto out;
if(trf)
itrunc(rip);
prele(rip);
if ((fp = falloc()) == NULL)
goto out;
fp->f_flag = m&(FREAD|FWRITE);
fp->f_inode = rip;
i = u.u_ar0[R0];
openi(rip, m&FWRITE);
if(u.u_error == 0)
return;
u.u_ofile[i] = NULL;
fp->f_count--;
out:
iput(rip);
}
/*
* close system call
*/
close()
{
register *fp;
fp = getf(u.u_ar0[R0]);
if(fp == NULL)
return;
u.u_ofile[u.u_ar0[R0]] = NULL;
closef(fp);
}
/*
* seek system call
*/
seek()
{
int n[2];
register *fp, t;
fp = getf(u.u_ar0[R0]);
if(fp == NULL)
return;
if(fp->f_flag&FPIPE) {
u.u_error = ESPIPE;
return;
}
t = u.u_arg[1];
if(t > 2) {
n[1] = u.u_arg[0]<<9;
n[0] = u.u_arg[0]>>7;
if(t == 3)
n[0] =& 0777;
} else {
n[1] = u.u_arg[0];
n[0] = 0;
if(t!=0 && n[1]<0)
n[0] = -1;
}
switch(t) {
case 1:
case 4:
n[0] =+ fp->f_offset[0];
dpadd(n, fp->f_offset[1]);
break;
default:
n[0] =+ fp->f_inode->i_size0&0377;
dpadd(n, fp->f_inode->i_size1);
case 0:
case 3:
;
}
fp->f_offset[1] = n[1];
fp->f_offset[0] = n[0];
}
/*
* link system call
*/
link()
{
register *ip, *xp;
extern uchar;
ip = namei(&uchar, 0);
if(ip == NULL)
return;
if(ip->i_nlink >= 127) {
u.u_error = EMLINK;
goto out;
}
if((ip->i_mode&IFMT)==IFDIR && !suser())
goto out;
/*
* unlock to avoid possibly hanging the namei
*/
ip->i_flag =& ~ILOCK;
u.u_dirp = u.u_arg[1];
xp = namei(&uchar, 1);
if(xp != NULL) {
u.u_error = EEXIST;
iput(xp);
}
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);
ip->i_nlink++;
ip->i_flag =| IUPD;
out:
iput(ip);
}
/*
* mknod system call
*/
mknod()
{
register *ip;
extern uchar;
if(suser()) {
ip = namei(&uchar, 1);
if(ip != NULL) {
u.u_error = EEXIST;
goto out;
}
}
if(u.u_error)
return;
ip = maknode(u.u_arg[1]);
if (ip==NULL)
return;
ip->i_addr[0] = u.u_arg[2];
out:
iput(ip);
}
/*
* sleep system call
* not to be confused with the sleep internal routine.
*/
sslep()
{
char *d[2];
spl7();
d[0] = time[0];
d[1] = time[1];
dpadd(d, u.u_ar0[R0]);
while(dpcmp(d[0], d[1], time[0], time[1]) > 0) {
if(dpcmp(tout[0], tout[1], time[0], time[1]) <= 0 ||
dpcmp(tout[0], tout[1], d[0], d[1]) > 0) {
tout[0] = d[0];
tout[1] = d[1];
}
sleep(tout, PSLEP);
}
spl0();
}
+194
View File
@@ -0,0 +1,194 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../reg.h"
#include "../buf.h"
#include "../filsys.h"
#include "../user.h"
#include "../inode.h"
#include "../file.h"
#include "../conf.h"
/*
* the fstat system call.
*/
fstat()
{
register *fp;
fp = getf(u.u_ar0[R0]);
if(fp == NULL)
return;
stat1(fp->f_inode, u.u_arg[0]);
}
/*
* the stat system call.
*/
stat()
{
register ip;
extern uchar;
ip = namei(&uchar, 0);
if(ip == NULL)
return;
stat1(ip, u.u_arg[1]);
iput(ip);
}
/*
* The basic routine for fstat and stat:
* get the inode and pass appropriate parts back.
*/
stat1(ip, ub)
int *ip;
{
register i, *bp, *cp;
iupdat(ip, time);
bp = bread(ip->i_dev, ldiv(ip->i_number+31, 16));
cp = bp->b_addr + 32*lrem(ip->i_number+31, 16) + 24;
ip = &(ip->i_dev);
for(i=0; i<14; i++) {
suword(ub, *ip++);
ub =+ 2;
}
for(i=0; i<4; i++) {
suword(ub, *cp++);
ub =+ 2;
}
brelse(bp);
}
/*
* the dup system call.
*/
dup()
{
register i, *fp;
fp = getf(u.u_ar0[R0]);
if(fp == NULL)
return;
if ((i = ufalloc()) < 0)
return;
u.u_ofile[i] = fp;
fp->f_count++;
}
/*
* the mount system call.
*/
smount()
{
int d;
register *ip;
register struct mount *mp, *smp;
extern uchar;
d = getmdev();
if(u.u_error)
return;
u.u_dirp = u.u_arg[1];
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(d == mp->m_dev)
goto out;
} else
if(smp == NULL)
smp = mp;
}
if(smp == NULL)
goto out;
(*bdevsw[d.d_major].d_open)(d, !u.u_arg[2]);
if(u.u_error)
goto out;
mp = bread(d, 1);
if(u.u_error) {
brelse(mp);
goto out1;
}
smp->m_inodp = ip;
smp->m_dev = d;
smp->m_bufp = getblk(NODEV);
bcopy(mp->b_addr, smp->m_bufp->b_addr, 256);
smp = smp->m_bufp->b_addr;
smp->s_ilock = 0;
smp->s_flock = 0;
smp->s_ronly = u.u_arg[2] & 1;
brelse(mp);
ip->i_flag =| IMOUNT;
prele(ip);
return;
out:
u.u_error = EBUSY;
out1:
iput(ip);
}
/*
* the umount system call.
*/
sumount()
{
int d;
register struct inode *ip;
register struct mount *mp;
update();
d = getmdev();
if(u.u_error)
return;
for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if(mp->m_bufp!=NULL && d==mp->m_dev)
goto found;
u.u_error = EINVAL;
return;
found:
for(ip = &inode[0]; ip < &inode[NINODE]; ip++)
if(ip->i_number!=0 && d==ip->i_dev) {
u.u_error = EBUSY;
return;
}
(*bdevsw[d.d_major].d_close)(d, 0);
ip = mp->m_inodp;
ip->i_flag =& ~IMOUNT;
iput(ip);
ip = mp->m_bufp;
mp->m_bufp = NULL;
brelse(ip);
}
/*
* 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.
*/
getmdev()
{
register d, *ip;
extern uchar;
ip = namei(&uchar, 0);
if(ip == NULL)
return;
if((ip->i_mode&IFMT) != IFBLK)
u.u_error = ENOTBLK;
d = ip->i_addr[0];
if(ip->i_addr[0].d_major >= nblkdev)
u.u_error = ENXIO;
iput(ip);
return(d);
}
+259
View File
@@ -0,0 +1,259 @@
#
/*
*/
/*
* Everything in this file is a routine implementing a system call.
*/
#include "../param.h"
#include "../user.h"
#include "../reg.h"
#include "../inode.h"
#include "../systm.h"
#include "../proc.h"
getswit()
{
u.u_ar0[R0] = SW->integ;
}
gtime()
{
u.u_ar0[R0] = time[0];
u.u_ar0[R1] = time[1];
}
stime()
{
if(suser()) {
time[0] = u.u_ar0[R0];
time[1] = u.u_ar0[R1];
wakeup(tout);
}
}
setuid()
{
register uid;
uid = u.u_ar0[R0].lobyte;
if(u.u_ruid == uid.lobyte || suser()) {
u.u_uid = uid;
u.u_procp->p_uid = uid;
u.u_ruid = uid;
}
}
getuid()
{
u.u_ar0[R0].lobyte = u.u_ruid;
u.u_ar0[R0].hibyte = u.u_uid;
}
setgid()
{
register gid;
gid = u.u_ar0[R0].lobyte;
if(u.u_rgid == gid.lobyte || suser()) {
u.u_gid = gid;
u.u_rgid = gid;
}
}
getgid()
{
u.u_ar0[R0].lobyte = u.u_rgid;
u.u_ar0[R0].hibyte = u.u_gid;
}
getpid()
{
u.u_ar0[R0] = u.u_procp->p_pid;
}
sync()
{
update();
}
nice()
{
register n;
n = u.u_ar0[R0];
if(n > 20)
n = 20;
if(n < 0 && !suser())
n = 0;
u.u_procp->p_nice = n;
}
/*
* Unlink system call.
* panic: unlink -- "cannot happen"
*/
unlink()
{
register *ip, *pp;
extern uchar;
pp = namei(&uchar, 2);
if(pp == NULL)
return;
prele(pp);
ip = iget(pp->i_dev, u.u_dent.u_ino);
if(ip == NULL)
panic("unlink -- iget");
if((ip->i_mode&IFMT)==IFDIR && !suser())
goto out;
u.u_offset[1] =- DIRSIZ+2;
u.u_base = &u.u_dent;
u.u_count = DIRSIZ+2;
u.u_dent.u_ino = 0;
writei(pp);
ip->i_nlink--;
ip->i_flag =| IUPD;
out:
iput(pp);
iput(ip);
}
chdir()
{
register *ip;
extern uchar;
ip = namei(&uchar, 0);
if(ip == NULL)
return;
if((ip->i_mode&IFMT) != IFDIR) {
u.u_error = ENOTDIR;
bad:
iput(ip);
return;
}
if(access(ip, IEXEC))
goto bad;
iput(u.u_cdir);
u.u_cdir = ip;
prele(ip);
}
chmod()
{
register *ip;
if ((ip = owner()) == NULL)
return;
ip->i_mode =& ~07777;
if (u.u_uid)
u.u_arg[1] =& ~ISVTX;
ip->i_mode =| u.u_arg[1]&07777;
ip->i_flag =| IUPD;
iput(ip);
}
chown()
{
register *ip;
if (!suser() || (ip = owner()) == NULL)
return;
ip->i_uid = u.u_arg[1].lobyte;
ip->i_gid = u.u_arg[1].hibyte;
ip->i_flag =| IUPD;
iput(ip);
}
/*
* Change modified date of file:
* time to r0-r1; sys smdate; file
* This call has been withdrawn because it messes up
* incremental dumps (pseudo-old files aren't dumped).
* It works though and you can uncomment it if you like.
smdate()
{
register struct inode *ip;
register int *tp;
int tbuf[2];
if ((ip = owner()) == NULL)
return;
ip->i_flag =| IUPD;
tp = &tbuf[2];
*--tp = u.u_ar0[R1];
*--tp = u.u_ar0[R0];
iupdat(ip, tp);
ip->i_flag =& ~IUPD;
iput(ip);
}
*/
ssig()
{
register a;
a = u.u_arg[0];
if(a<=0 || a>=NSIG || a ==SIGKIL) {
u.u_error = EINVAL;
return;
}
u.u_ar0[R0] = u.u_signal[a];
u.u_signal[a] = u.u_arg[1];
if(u.u_procp->p_sig == a)
u.u_procp->p_sig = 0;
}
kill()
{
register struct proc *p, *q;
register a;
int f;
f = 0;
a = u.u_ar0[R0];
q = u.u_procp;
for(p = &proc[0]; p < &proc[NPROC]; p++) {
if(p == q)
continue;
if(a != 0 && p->p_pid != a)
continue;
if(a == 0 && (p->p_ttyp != q->p_ttyp || p <= &proc[1]))
continue;
if(u.u_uid != 0 && u.u_uid != p->p_uid)
continue;
f++;
psignal(p, u.u_arg[0]);
}
if(f == 0)
u.u_error = ESRCH;
}
times()
{
register *p;
for(p = &u.u_utime; p < &u.u_utime+6;) {
suword(u.u_arg[0], *p++);
u.u_arg[0] =+ 2;
}
}
profil()
{
u.u_prof[0] = u.u_arg[0] & ~1; /* base of sample buf */
u.u_prof[1] = u.u_arg[1]; /* size of same */
u.u_prof[2] = u.u_arg[2]; /* pc offset */
u.u_prof[3] = (u.u_arg[3]>>1) & 077777; /* pc scale */
}
+77
View File
@@ -0,0 +1,77 @@
#
/*
*/
/*
* 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.
*/
int sysent[]
{
0, &nullsys, /* 0 = indir */
0, &rexit, /* 1 = exit */
0, &fork, /* 2 = fork */
2, &read, /* 3 = read */
2, &write, /* 4 = write */
2, &open, /* 5 = open */
0, &close, /* 6 = close */
0, &wait, /* 7 = wait */
2, &creat, /* 8 = creat */
2, &link, /* 9 = link */
1, &unlink, /* 10 = unlink */
2, &exec, /* 11 = exec */
1, &chdir, /* 12 = chdir */
0, &gtime, /* 13 = time */
3, &mknod, /* 14 = mknod */
2, &chmod, /* 15 = chmod */
2, &chown, /* 16 = chown */
1, &sbreak, /* 17 = break */
2, &stat, /* 18 = stat */
2, &seek, /* 19 = seek */
0, &getpid, /* 20 = getpid */
3, &smount, /* 21 = mount */
1, &sumount, /* 22 = umount */
0, &setuid, /* 23 = setuid */
0, &getuid, /* 24 = getuid */
0, &stime, /* 25 = stime */
3, &ptrace, /* 26 = ptrace */
0, &nosys, /* 27 = x */
1, &fstat, /* 28 = fstat */
0, &nosys, /* 29 = x */
1, &nullsys, /* 30 = smdate; inoperative */
1, &stty, /* 31 = stty */
1, &gtty, /* 32 = gtty */
0, &nosys, /* 33 = x */
0, &nice, /* 34 = nice */
0, &sslep, /* 35 = sleep */
0, &sync, /* 36 = sync */
1, &kill, /* 37 = kill */
0, &getswit, /* 38 = switch */
0, &nosys, /* 39 = x */
0, &nosys, /* 40 = x */
0, &dup, /* 41 = dup */
0, &pipe, /* 42 = pipe */
1, &times, /* 43 = times */
4, &profil, /* 44 = prof */
0, &nosys, /* 45 = tiu */
0, &setgid, /* 46 = setgid */
0, &getgid, /* 47 = getgid */
2, &ssig, /* 48 = sig */
0, &nosys, /* 49 = x */
0, &nosys, /* 50 = x */
0, &nosys, /* 51 = x */
0, &nosys, /* 52 = x */
0, &nosys, /* 53 = x */
0, &nosys, /* 54 = x */
0, &nosys, /* 55 = x */
0, &nosys, /* 56 = x */
0, &nosys, /* 57 = x */
0, &nosys, /* 58 = x */
0, &nosys, /* 59 = x */
0, &nosys, /* 60 = x */
0, &nosys, /* 61 = x */
0, &nosys, /* 62 = x */
0, &nosys /* 63 = x */
};
+156
View File
@@ -0,0 +1,156 @@
#
/*
*/
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../proc.h"
#include "../text.h"
#include "../inode.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
* panic: swap error -- IO error
*/
xswap(p, ff, os)
int *p;
{
register *rp, a;
rp = p;
if(os == 0)
os = rp->p_size;
a = malloc(swapmap, (rp->p_size+7)/8);
if(a == NULL)
panic("out of swap space");
xccdec(rp->p_textp);
rp->p_flag =| SLOCK;
if(swap(a, rp->p_addr, os, 0))
panic("swap error");
if(ff)
mfree(coremap, os, rp->p_addr);
rp->p_addr = a;
rp->p_flag =& ~(SLOAD|SLOCK);
rp->p_time = 0;
if(runout) {
runout = 0;
wakeup(&runout);
}
}
/*
* relinquish use of the shared text segment
* of a process.
*/
xfree()
{
register *xp, *ip;
if((xp=u.u_procp->p_textp) != NULL) {
u.u_procp->p_textp = NULL;
xccdec(xp);
if(--xp->x_count == 0) {
ip = xp->x_iptr;
if((ip->i_mode&ISVTX) == 0) {
xp->x_iptr = NULL;
mfree(swapmap, (xp->x_size+7)/8, xp->x_daddr);
ip->i_flag =& ~ITEXT;
iput(ip);
}
}
}
}
/*
* 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) and established in the swap space.
* If it is being used, but is not currently in core,
* a swap has to be done to get it back.
* The full coroutine glory has to be invoked--
* see slp.c-- because if the calling process
* is misplaced in core the text image might not fit.
* Quite possibly the code after "out:" could check to
* see if the text does fit and simply swap it in.
*
* panic: out of swap space
*/
xalloc(ip)
int *ip;
{
register struct text *xp;
register *rp, ts;
if(u.u_arg[1] == 0)
return;
rp = NULL;
for(xp = &text[0]; xp < &text[NTEXT]; xp++)
if(xp->x_iptr == NULL) {
if(rp == NULL)
rp = xp;
} else
if(xp->x_iptr == ip) {
xp->x_count++;
u.u_procp->p_textp = xp;
goto out;
}
if((xp=rp) == NULL)
panic("out of text");
xp->x_count = 1;
xp->x_ccount = 0;
xp->x_iptr = ip;
ts = ((u.u_arg[1]+63)>>6) & 01777;
xp->x_size = ts;
if((xp->x_daddr = malloc(swapmap, (ts+7)/8)) == NULL)
panic("out of swap space");
expand(USIZE+ts);
estabur(0, ts, 0, 0);
u.u_count = u.u_arg[1];
u.u_offset[1] = 020;
u.u_base = 0;
readi(ip);
rp = u.u_procp;
rp->p_flag =| SLOCK;
swap(xp->x_daddr, rp->p_addr+USIZE, ts, 0);
rp->p_flag =& ~SLOCK;
rp->p_textp = xp;
rp = ip;
rp->i_flag =| ITEXT;
rp->i_count++;
expand(USIZE);
out:
if(xp->x_ccount == 0) {
savu(u.u_rsav);
savu(u.u_ssav);
xswap(u.u_procp, 1, 0);
u.u_procp->p_flag =| SSWAP;
swtch();
/* no return */
}
xp->x_ccount++;
}
/*
* Decrement the in-core usage count of a shared text segment.
* When it drops to zero, free the core space.
*/
xccdec(xp)
int *xp;
{
register *rp;
if((rp=xp)!=NULL && rp->x_ccount!=0)
if(--rp->x_ccount == 0)
mfree(coremap, rp->x_size, rp->x_caddr);
}
+212
View File
@@ -0,0 +1,212 @@
#
#include "../param.h"
#include "../systm.h"
#include "../user.h"
#include "../proc.h"
#include "../reg.h"
#include "../seg.h"
#define EBIT 1 /* user error bit in PS: C-bit */
#define UMODE 0170000 /* user-mode bits in PS word */
#define SETD 0170011 /* SETD instruction */
#define SYS 0104400 /* sys (trap) instruction */
#define USER 020 /* user-mode flag added to dev */
/*
* structure of the system entry table (sysent.c)
*/
struct sysent {
int count; /* argument count */
int (*call)(); /* name of handler */
} sysent[64];
/*
* Offsets of the user's registers relative to
* the saved r0. See reg.h
*/
char regloc[9]
{
R0, R1, R2, R3, R4, R5, R6, R7, RPS
};
/*
* Called from l40.s or l45.s when a processor trap occurs.
* The arguments are the words saved on the system stack
* by the hardware and software during the trap processing.
* Their order is dictated by the hardware and the details
* of C's calling sequence. They are peculiar in that
* this call is not 'by value' and changed user registers
* get copied back on return.
* dev is the kind of trap that occurred.
*/
trap(dev, sp, r1, nps, r0, pc, ps)
{
register i, a;
register struct sysent *callp;
savfp();
if ((ps&UMODE) == UMODE)
dev =| USER;
u.u_ar0 = &r0;
switch(dev) {
/*
* Trap not expected.
* Usually a kernel mode bus error.
* The numbers printed are used to
* find the hardware PS/PC as follows.
* (all numbers in octal 18 bits)
* address_of_saved_ps =
* (ka6*0100) + aps - 0140000;
* address_of_saved_pc =
* address_of_saved_ps - 2;
*/
default:
printf("ka6 = %o\n", *ka6);
printf("aps = %o\n", &ps);
printf("trap type %o\n", dev);
panic("trap");
case 0+USER: /* bus error */
i = SIGBUS;
break;
/*
* If illegal instructions are not
* being caught and the offending instruction
* is a SETD, the trap is ignored.
* This is because C produces a SETD at
* the beginning of every program which
* will trap on CPUs without 11/45 FPU.
*/
case 1+USER: /* illegal instruction */
if(fuiword(pc-2) == SETD && u.u_signal[SIGINS] == 0)
goto out;
i = SIGINS;
break;
case 2+USER: /* bpt or trace */
i = SIGTRC;
break;
case 3+USER: /* iot */
i = SIGIOT;
break;
case 5+USER: /* emt */
i = SIGEMT;
break;
case 6+USER: /* sys call */
u.u_error = 0;
ps =& ~EBIT;
callp = &sysent[fuiword(pc-2)&077];
if (callp == sysent) { /* indirect */
a = fuiword(pc);
pc =+ 2;
i = fuword(a);
if ((i & ~077) != SYS)
i = 077; /* illegal */
callp = &sysent[i&077];
for(i=0; i<callp->count; i++)
u.u_arg[i] = fuword(a =+ 2);
} else {
for(i=0; i<callp->count; i++) {
u.u_arg[i] = fuiword(pc);
pc =+ 2;
}
}
u.u_dirp = u.u_arg[0];
trap1(callp->call);
if(u.u_intflg)
u.u_error = EINTR;
if(u.u_error < 100) {
if(u.u_error) {
ps =| EBIT;
r0 = u.u_error;
}
goto out;
}
i = SIGSYS;
break;
/*
* Since the floating exception is an
* imprecise trap, a user generated
* trap may actually come from kernel
* mode. In this case, a signal is sent
* to the current process to be picked
* up later.
*/
case 8: /* floating exception */
psignal(u.u_procp, SIGFPT);
return;
case 8+USER:
i = SIGFPT;
break;
/*
* If the user SP is below the stack segment,
* grow the stack automatically.
* This relies on the ability of the hardware
* to restart a half executed instruction.
* On the 11/40 this is not the case and
* the routine backup/l40.s may fail.
* The classic example is on the instruction
* cmp -(sp),-(sp)
*/
case 9+USER: /* segmentation exception */
a = sp;
if(backup(u.u_ar0) == 0)
if(grow(a))
goto out;
i = SIGSEG;
break;
}
psignal(u.u_procp, i);
out:
if(issig())
psig();
setpri(u.u_procp);
}
/*
* Call the system-entry routine f (out of the
* sysent table). This is a subroutine for trap, and
* not in-line, because if a signal occurs
* during processing, an (abnormal) return is simulated from
* the last caller to savu(qsav); if this took place
* inside of trap, it wouldn't have a chance to clean up.
*
* If this occurs, the return takes place without
* clearing u_intflg; if it's still set, trap
* marks an error which means that a system
* call (like read on a typewriter) got interrupted
* by a signal.
*/
trap1(f)
int (*f)();
{
u.u_intflg = 1;
savu(u.u_qsav);
(*f)();
u.u_intflg = 0;
}
/*
* nonexistent system call-- set fatal error code.
*/
nosys()
{
u.u_error = 100;
}
/*
* Ignored system call
*/
nullsys()
{
}