DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦d56983a01⟧ TextFile

    Length: 14233 (0x3799)
    Types: TextFile
    Notes: UNIX file
    Names: »seg.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦2d53db1df⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »sys/coh/seg.c« 

TextFile

/* (-lgl
 * 	The information contained herein is a trade secret of Mark Williams
 * 	Company, and  is confidential information.  It is provided  under a
 * 	license agreement,  and may be  copied or disclosed  only under the
 * 	terms of  that agreement.  Any  reproduction or disclosure  of this
 * 	material without the express written authorization of Mark Williams
 * 	Company or persuant to the license agreement is unlawful.
 * 
 * 	COHERENT Version 0.7.3
 * 	Copyright (c) 1982, 1983, 1984.
 * 	An unpublished work by Mark Williams Company, Chicago.
 * 	All rights reserved.
 -lgl) */
/*
 * Coherent.
 * Segment manipulation.
 */
#include <coherent.h>
#include <buf.h>
#include <errno.h>
#include <ino.h>
#include <inode.h>
#include <proc.h>
#include <sched.h>
#include <seg.h>
#include <uproc.h>

/*
 * Initialisation code.
 */
seginit()
{
	segmq.s_forw = &segmq;
	segmq.s_back = &segmq;
	segdq.s_forw = &segdq;
	segdq.s_back = &segdq;
}

/*
 * Given an inode, `ip', and flags, `ff', describing a segment associated
 * with the inode, see if the segment already exists and if so, return a
 * copy.  If the segment does not exists, allocate the segment having size
 * `ss', and read the segment using the inode at seek offset `dq' with a
 * size of `ds'.
 */
SEG *
ssalloc(rp, ip, ff, ss, dq, ds)
int *rp;
register INODE *ip;
size_t ss;
size_t dq;
size_t ds;
{
	register SEG *sp;
	register int f;

	*rp = -1;
	if (ss == 0) {
		*rp = 1;
		return (NULL);
	}
	lock(seglink);
	f = ff & (SFSHRX|SFTEXT);

	/*
	 * Look for the segment in the memory queue.
	 */
	for (sp=segmq.s_forw; sp!=&segmq; sp=sp->s_forw) {
		if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) {
			unlock(seglink);
			sp = segdupl(sp);
			segfinm(sp);
			*rp = 1;
			return (sp);
		}
	}

	/*
	 * Look for the segment on the disk queue.
	 */
	for (sp=segdq.s_forw; sp!=&segdq; sp=sp->s_forw) {
		if (sp->s_ip==ip && (sp->s_flags&(SFSHRX|SFTEXT))==f) {
			unlock(seglink);
			sp = segdupl(sp);
			segfinm(sp);
			*rp = 1;
			return (sp);
		}
	}
	unlock(seglink);

	/*
	 * Allocate and create the segment.
	 */
	if ((sp=salloc(ss, ff)) == NULL)
		return (NULL);
	if (exsread(sp, ip, ds, dq, (size_t)0) == 0)
		return (NULL);
	if ((ff&SFSHRX) != 0) {
		sp->s_ip = ip;
		ip->i_refc++;
	}
	*rp = 0;
	return (sp);
}

/*
 * Given a pointer to a newly created process, copy all of our segments
 * into the given process.
 */
segadup(cpp)
register PROC *cpp;
{
	register SEG *sp;
	register int n;
	register PROC *pp;

	pp = SELF;
	cpp->p_flags |= PFSWIO;
	for (n=0; n<NUSEG; n++) {
		if ((sp=pp->p_segp[n]) == NULL)
			continue;
		if ((sp=segdupl(sp)) == NULL)
			break;
		cpp->p_segp[n] = sp;
		if ((sp->s_flags&SFCORE) == 0)
			cpp->p_flags &= ~PFCORE;
	}
	if (n < NUSEG) {
		while (n > 0) {
			if ((sp=cpp->p_segp[--n]) != NULL) {
				sfree(sp);
				cpp->p_segp[n] = NULL;
			}
		}
	}
	cpp->p_flags &= ~PFSWIO;
	return (n);
}

/*
 * Duplicate a segment.
 */
SEG *
segdupl(sp)
register SEG *sp;
{
	register SEG *sp1;
	register size_t ss;

	if ((sp->s_flags&SFSHRX) != 0) {
		sp->s_urefc++;
		sp->s_lrefc++;
		return (sp);
	}
	ss = ctob((size_t)sp->s_size);
	if ((sp->s_flags&SFCORE) == 0)
		panic("Cannot duplicate non shared swapped segment");
	if ((sp1=salloc(ss, sp->s_flags|SFNSWP|SFNCLR)) == NULL)
		sp1 = segdupd(sp);
	else {
		sp1->s_flags = sp->s_flags;
		slrcopy(sp->s_mbase, sp1->s_mbase, sp->s_size);
	}
	return (sp1);
}

/*
 * Allocate a segment `n' bytes long.  `f' contains some pseudo flags.
 */
SEG *
salloc(n, f)
size_t n;
{
	register SEG *sp;
	register saddr_t s;
	register int r;

	r = (f&(SFSYST|SFHIGH|SFTEXT|SFSHRX|SFDOWN)) | SFCORE;
	s = btocru(n);
	lock(seglink);
	sp = sxalloc(s, f);
	unlock(seglink);
	if (sp != NULL)
		sp->s_flags = r;
	else {
		if ((f&SFNSWP) != 0)
			return (NULL);
		if ((sp=kalloc(sizeof(SEG))) == NULL)
			return (NULL);
		sp->s_forw = sp;
		sp->s_back = sp;
		sp->s_flags = r;
		sp->s_urefc = 1;
		sp->s_lrefc = 1;
		if (segsext(sp, s) == NULL) {
			kfree(sp);
			return (NULL);
		}
	}
	if ((f&SFNCLR) == 0)
		sclear(sp->s_mbase, s);
	return (sp);
}

/*
 * Free the given segment pointer.
 */
sfree(sp)
register SEG *sp;
{
	register INODE *ip;

	--sp->s_lrefc;
	if (--sp->s_urefc == 0) {
		if (sp->s_lrefc != 0)
			panic("Bad segment count");
		if ((ip=sp->s_ip) != NULL)
			ldetach(ip);
		lock(seglink);
		sp->s_back->s_forw = sp->s_forw;
		sp->s_forw->s_back = sp->s_back;
		unlock(seglink);
		kfree(sp);
	}
}

/*
 * Grow or shrink the segment `sp' so that it has size `n'.
 */
seggrow(sp, n)
register SEG *sp;
size_t n;
{
	register SEG *sp1;
	register saddr_t s;
	register saddr_t d;
	register saddr_t pb;
	register saddr_t nb;
	register int dowflag;

	dowflag = sp->s_flags&SFDOWN;
	s = btocru(n);

	/*
	 * Size of new segment is smaller or the same size as the old
	 * segment.
	 */
	lock(seglink);
	d = s - sp->s_size;
	if (s <= sp->s_size) {
		if (dowflag)
			sp->s_mbase -= d;
		sp->s_size = s;
		unlock(seglink);
		return (1);
	}
	if ((sp1=sp->s_back) == &segmq)
		pb = corebot;
	else
		pb = sp1->s_mbase + sp1->s_size;
	if ((sp1=sp->s_forw) == &segmq)
		nb = coretop;
	else
		nb = sp1->s_mbase;

	/*
	 * If the segment does not grow down, see if there is enough
	 * space after the segment.
	 */
	if (dowflag==0 && nb-sp->s_mbase>=s) {
		sclear(sp->s_mbase+sp->s_size, d);
		sp->s_size = s;
		unlock(seglink);
		return (1);
	}

	/*
	 * If the segment grows down, see if there is enough space
	 * before the segment.
	 */
	if (dowflag!=0 && sp->s_mbase+sp->s_size-pb>=s) {
		sp->s_mbase -= d;
		sp->s_size = s;
		sclear(sp->s_mbase, d);
		unlock(seglink);
		return (1);
	}

	/*
	 * Is there enough space in total counting the gaps on either
	 * side of us?
	 */
	if (nb-pb >= s) {
		if (dowflag == 0) {
			slrcopy(sp->s_mbase, pb, sp->s_size);
			sclear(pb+sp->s_size, d);
			sp->s_mbase = pb;
		} else {
			srlcopy(sp->s_mbase, nb-sp->s_size, sp->s_size);
			sclear(nb-s, d);
			sp->s_mbase = nb-s;
		}
		sp->s_size = s;
		unlock(seglink);
		return (1);
	}

	/*
	 * Try to allocate a segment somewhere else on the segment queue
	 * and copy ourselves there.
	 */
	unlock(seglink);
	if ((sp1=salloc(ctob((size_t)s), sp->s_flags|SFNSWP|SFNCLR)) != NULL) {
		if (dowflag == 0) {
			slrcopy(sp->s_mbase, sp1->s_mbase, sp->s_size);
			sclear(sp1->s_mbase+sp->s_size, d);
		} else {
			slrcopy(sp->s_mbase, sp1->s_mbase+d, sp->s_size);
			sclear(sp1->s_mbase, d);
		}
		lock(seglink);
		satcopy(sp, sp1);
		unlock(seglink);
		return (1);
	}

	/*
	 * Last chance.  Extend the segment by swapping it.
	 */
	if (segsext(sp, s) != NULL) {
		if (dowflag == 0)
			sclear(sp->s_mbase+s-d, d);
		else {
			srlcopy(sp->s_mbase, sp->s_mbase+d, s-d);
			sclear(sp->s_mbase, d);
		}
		return (1);
	}

	/*
	 * At least we tried.
	 */
	return (0);
}

/*
 * Given a segment pointer, `sp' and a segment size, grow the given segment
 * to the given size.
 */
segsize(sp, s2)
register SEG *sp;
vaddr_t s2;
{
	register vaddr_t s1;

	s1 = (vaddr_t)ctob(sp->s_size);
	if (seggrow(sp, (size_t)s2) == 0) {
		u.u_error = ENOMEM;
		return;
	}
	if (sproto() == 0)
		if (seggrow(sp, (size_t)s1)==0 || sproto()==0)
			sendsig(SIGSEGV, SELF);
	segload();
}

/*
 * Grow the segment `sp1' to the size `s' by swapping it out
 * and back in.  The segment may not be locked.
 */
SEG *
segsext(sp1, s)
register SEG *sp1;
register saddr_t s;
{
	register SEG *sp2;

#ifndef NOMONITOR
	if (swmflag)
		printf("Segsext(%p, %u)\n", SELF, SELF->p_pid);
#endif
	if (sexflag == 0) {
		u.u_error = ENOMEM;
		return (NULL);
	}
	lock(seglink);
	if ((sp2=sdalloc(s)) == NULL) {
		unlock(seglink);
		return (NULL);
	}
	unlock(seglink);
	sp1->s_lrefc++;
	if (sp1->s_size != 0)
		swapio(1, sp1->s_mbase, sp2->s_dbase, sp1->s_size);
	lock(seglink);
	satcopy(sp1, sp2);
	unlock(seglink);
	sp1->s_flags &= ~SFCORE;
	--sp1->s_lrefc;
	segfinm(sp1);
	return (sp1);
}

/*
 * Force the given segment to be in memory.  One can only force
 * one segment to be in memory at a time.
 */
segfinm(sp)
register SEG *sp;
{
	register PROC *pp;
	register int s;

	if ((sp->s_flags&SFCORE) != 0)
		return;
	pp = SELF;
	pp->p_segp[SIAUXIL] = sp;
	pp->p_flags &= ~PFCORE;
	s = sphi();
	setrun(pp);
	dispatch();
	spl(s);
	pp->p_segp[SIAUXIL] = NULL;
}

/*
 * Make a copy of the segment `sp1' which is in memory by writing
 * it out to disk.
 */
SEG *
segdupd(sp1)
register SEG *sp1;
{
	register SEG *sp2;

	if (sexflag == 0)
		return (NULL);
	lock(seglink);
	if ((sp2=sdalloc(sp1->s_size)) == NULL) {
		unlock(seglink);
		return (NULL);
	}
	sp1->s_lrefc++;
	unlock(seglink);
	swapio(1, sp1->s_mbase, sp2->s_dbase, sp1->s_size);
	--sp1->s_lrefc;
	sp2->s_ip = sp1->s_ip;
	sp2->s_flags = sp1->s_flags & ~SFCORE;
	sp2->s_size = sp1->s_size;
	return (sp2);
}

/*
 * Given a flag, a core address in clicks, a disk address and a count in
 * clicks, perform an I/O operation between core and disk.  If `flag' is
 * set, the transfer is to the disk otherwise it is to memory.  As you may
 * have guessed, this is used by the swapper.
 */
swapio(f, c, d, n)
saddr_t c;
daddr_t d;
saddr_t n;
{
	register BUF *bp;
	register int s;
	register int nb;

#ifndef NOMONITOR
	if (swmflag > 1)
		printf("swapio(%s,%x,%x,%x)\n",(f?"out":"in"),c,(int)d,n);
#endif
	if (d < swapbot || d+stod(n) > swaptop
	 || c < corebot || c+n > coretop)
		panic("Swapio bad parameter");
	bp = &swapbuf;
	lock(bp->b_gate);
	SELF->p_flags |= PFSWIO;
	while (n != 0) {
		nb = (n > btocrd(SCHUNK)) ? SCHUNK : ctob(n);
		bp->b_flag = BFNTP;
		bp->b_req = f ? BWRITE : BREAD;
		bp->b_dev = swapdev;
		bp->b_bno = d;
		bp->b_paddr = ctob((paddr_t)c);
		bp->b_count = nb;
		s = sphi();
		dblock(swapdev, bp);
		while ((bp->b_flag&BFNTP) != 0)
			sleep((char *)bp, CVBLKIO, IVBLKIO, SVBLKIO);
		spl(s);
		if ((bp->b_flag&BFERR) != 0)
			panic("Swapio error");
		c += btocrd(SCHUNK);
		d += stod(btocrd(SCHUNK));
		n -= btocrd(nb);
	}
	unlock(bp->b_gate);
	SELF->p_flags &= ~PFSWIO;
}

/*
 * Make the segment descriptor pointed to by `sp1' have the attributes
 * of `sp2' including it's position in the segment queue and release
 * `sp2'.  `seglink' must be locked when this routine is called.
 */
satcopy(sp1, sp2)
register SEG *sp1;
register SEG *sp2;
{
	sp1->s_back->s_forw = sp1->s_forw;
	sp1->s_forw->s_back = sp1->s_back;
	sp2->s_back->s_forw = sp1;
	sp1->s_back = sp2->s_back;
	sp2->s_forw->s_back = sp1;
	sp1->s_forw = sp2->s_forw;
	sp1->s_size = sp2->s_size;
	sp1->s_mbase = sp2->s_mbase;
	sp1->s_dbase = sp2->s_dbase;
	kfree(sp2);
}

/*
 * Allocate a segment on disk that is `n' clicks long.
 * The `seglink' gate should be locked before this routine is called.
 */
SEG *
sdalloc(s)
saddr_t s;
{
	register SEG *sp1;
	register SEG *sp2;
	register daddr_t d;
	register daddr_t d1;
	register daddr_t d2;

	d = stod(s);
	d1 = swapbot;
	sp1 = &segdq;
	do {
		if (d1 >= swaptop)
			return (NULL);
		if ((sp1=sp1->s_forw) != &segdq)
			d2 = sp1->s_dbase;
		else
			d2 = swaptop;
		if (d2-d1 >= d) {
			if ((sp2=kalloc(sizeof(SEG))) == NULL)
				return (NULL);
			sp1->s_back->s_forw = sp2;
			sp2->s_back = sp1->s_back;
			sp1->s_back = sp2;
			sp2->s_forw = sp1;
			sp2->s_urefc = 1;
			sp2->s_lrefc = 1;
			sp2->s_size = s;
			sp2->s_dbase = d1;
			return (sp2);
		}
		d1 = sp1->s_dbase + stod(sp1->s_size);
	} while (sp1 != &segdq);
	return (NULL);
}

/*
 * Allocate a segment in memory that is `n' clicks long.
 * The `seglink' gate should be locked before this routine is called.
 */
SEG *
smalloc(s)
saddr_t s;
{
	register SEG *sp1;
	register SEG *sp2;
	register saddr_t s1;
	register saddr_t s2;

	s1 = corebot;
	sp1 = &segmq;
	do {
		if ((sp1=sp1->s_forw) != &segmq)
			s2 = sp1->s_mbase;
		else
			s2 = coretop;
		if (s2-s1 >= s) {
			if ((sp2=kalloc(sizeof (SEG))) == NULL)
				return (NULL);
			sp1->s_back->s_forw = sp2;
			sp2->s_back = sp1->s_back;
			sp1->s_back = sp2;
			sp2->s_forw = sp1;
			sp2->s_urefc = 1;
			sp2->s_lrefc = 1;
			sp2->s_size = s;
			sp2->s_mbase = s1;
			return (sp2);
		}
		s1 = sp1->s_mbase + sp1->s_size;
	} while (sp1 != &segmq);
	return (NULL);
}

/*
 * Allocate a segment from the high end of memory that is `n' clicks long.
 * The `seglink' gate should be locked before this routine is called.
 */
SEG *
shalloc(s)
saddr_t s;
{
	register SEG *sp1;
	register SEG *sp2;
	register saddr_t s1;
	register saddr_t s2;

	sp1 = &segmq;
	s2 = coretop;
	do {
		if ((sp1=sp1->s_back) != &segmq)
			s1 = sp1->s_mbase + sp1->s_size;
		else
			s1 = corebot;
		if (s2-s1 >= s) {
			if ((sp2=kalloc(sizeof (SEG))) == NULL)
				return (NULL);
			sp1->s_forw->s_back = sp2;
			sp2->s_forw = sp1->s_forw;
			sp1->s_forw = sp2;
			sp2->s_back = sp1;
			sp2->s_urefc = 1;
			sp2->s_lrefc = 1;
			sp2->s_size = s;
			sp2->s_mbase = s2-s;
			return (sp2);
		}
		s2 = sp1->s_mbase;
	} while (sp1 != &segmq);
	return (NULL);
}

/*
 * Set up `SR' structure in user area from segments descriptors in
 * process structure.  Also set up the user segmentation registers.
 */
sproto()
{
	register int n;
	register SEG *sp;
	register SR *srp;
	register PROC *pp;

	pp = SELF;
	kclear(u.u_segl, sizeof(u.u_segl));
	for (n=0; n<NUSEG; n++) {
		if ((sp=pp->p_segp[n]) == NULL)
			continue;
		srp = &u.u_segl[n];
		if (n == SIUSERP)
			srp->sr_base = &u;
		else
			srp->sr_flag |= SRFPMAP;
		if (n!=SISTEXT && n!=SISDATA)
			srp->sr_flag |= SRFDUMP;
		if (n!=SIUSERP && n!=SISTEXT && n!=SIPTEXT)
			srp->sr_flag |= SRFDATA;
		srp->sr_size = ctob(sp->s_size);
		srp->sr_segp = sp;
	}
	pp->p_flags &= ~PFSPROTO;
	return (mproto());
}

/*
 * Segment consistency checks for the paranoid.
segchk()
{
	register SEG *sp;
	register saddr_t s;
	register daddr_t d;
	register int nbad;

	nbad = 0;
	sp = &segmq;
	s = corebot;
	while ((sp=sp->s_forw) != &segmq) {
		if (sp->s_mbase < s)
			nbad += badseg("mem", sp->s_mbase, 0);
		s = sp->s_mbase + sp->s_size;
	}
	if (coretop < s)
		nbad += badseg("mem", sp->s_back->s_mbase, sp->s_back->s_size);
	sp = &segdq;
	d = swapbot;
	while ((sp=sp->s_forw) != &segdq) {
		if (sp->s_dbase < d)
			nbad += badseg("disk", (int)sp->s_dbase, 0);
		d = sp->s_dbase + stod(sp->s_size);
	}
	if (swaptop < d)
		nbad += badseg("disk", (int)sp->s_back->s_dbase, sp->s_back->s_size);
}

badseg(t, b, s)
char *t;
int b, s;
{
	printf("Bad %s segment %x for %x clicks\n", t, b, s);
	return (1);
}
*/