static char rcsid[] = "$Header: kern_mman.c,v 820.1 86/12/04 19:58:01 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984, 1985			*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*	kern_mman.c	6.1	83/07/29	*/

#include "../machine/reg.h"
#include "../machine/psl.h"
#include "../machine/pte.h"
#ifdef s32
#include "../machine/cpu.h"
#endif s32

#include "../h/param.h"
#include "../h/systm.h"
#ifdef s32
#include "../s32/debug.h"
#endif s32
#include "../h/map.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/buf.h"
#include "../h/inode.h"
#include "../h/seg.h"
#include "../h/acct.h"
#include "../h/wait.h"
#include "../h/vm.h"
#include "../h/text.h"
#include "../h/file.h"
#include "../h/vadvise.h"
#include "../h/cmap.h"
#include "../h/trace.h"
#include "../h/mman.h"
#include "../h/conf.h"

short	sizeofcmapEntry = sizeof(struct cmap);	/* # bytes in an entry */

sbrk()
{

}

sstk()
{

}

getpagesize()
{

	u.u_r.r_val1 = NBPG * CLSIZE;
}

smmap()
{
#ifdef sun
	struct a {
		caddr_t	addr;
		int	len;
		int	prot;
		int	share;
		int	fd;
		off_t	pos;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	register struct inode *ip;
	register struct fpte *pte;
	int off;
	int fv, lv, pm;
	dev_t dev;
	int (*mapfun)();
	extern struct file *getinode();

	fp = getinode(uap->fd);
	if (fp == NULL)
		return;
	ip = (struct inode *)fp->f_data;
	if ((ip->i_mode & IFMT) != IFCHR) {
		u.u_error = EINVAL;
		return;
	}
	dev = ip->i_rdev;
	mapfun = cdevsw[major(dev)].d_mmap;
	if (mapfun == NULL) {
		u.u_error = EINVAL;
		return;
	}
	if (((int)uap->addr & CLOFSET) || (uap->len & CLOFSET) ||
	    (uap->pos & CLOFSET)) {
		u.u_error = EINVAL;
		return;
	}
	if ((uap->prot & PROT_WRITE) && (fp->f_flag&FWRITE) == 0) {
		u.u_error = EINVAL;
		return;
	}
	if ((uap->prot & PROT_READ) && (fp->f_flag&FREAD) == 0) {
		u.u_error = EINVAL;
		return;
	}
	if (uap->share != MAP_SHARED) {
		u.u_error = EINVAL;
		return;
	}
	fv = btop(uap->addr);
	lv = btop(uap->addr + uap->len - 1);
	if (lv < fv || !isadsv(u.u_procp, fv) || !isadsv(u.u_procp, lv)) {
		u.u_error = EINVAL;
		return;
	}
	for (off=0; off<uap->len; off += NBPG) {
		if ((*mapfun)(dev, uap->pos+off, uap->prot) == -1) {
			u.u_error = EINVAL;
			return;
		}
	}
	if (uap->prot & PROT_WRITE)
		pm = PG_UW;
	else
		pm = PG_URKR;
	for (off = 0; off < uap->len; off += NBPG) {
		pte = (struct fpte *)vtopte(u.u_procp, fv);
		u.u_procp->p_rssize -= vmemfree(pte, 1);
		*(int *)pte = pm;
		pte->pg_v = 1;
		pte->pg_fod = 1;
		pte->pg_fileno = uap->fd;
		pte->pg_blkno = (*mapfun)(dev, uap->pos+off, uap->prot);
		fv++;
	}
	u.u_procp->p_flag |= SPTECHG;
	u.u_pofile[uap->fd] |= UF_MAPPED;
#endif
}

mremap()
{

}

munmap()
{
#ifdef sun
	register struct a {
		caddr_t	addr;
		int	len;
	} *uap = (struct a *)u.u_ap;
	int off;
	int fv, lv;
	register struct pte *pte;

	if (((int)uap->addr & CLOFSET) || (uap->len & CLOFSET)) {
		u.u_error = EINVAL;
		return;
	}
	fv = btop(uap->addr);
	lv = btop(uap->addr + uap->len - 1);
	if (lv < fv || !isadsv(u.u_procp, fv) || !isadsv(u.u_procp, lv)) {
		u.u_error = EINVAL;
		return;
	}
	for (off = 0; off < uap->len; off += NBPG) {
		pte = vtopte(u.u_procp, fv);
		u.u_procp->p_rssize -= vmemfree(pte, 1);
		*(int *)pte = (PG_UW|PG_FOD);
		((struct fpte *)pte)->pg_fileno = PG_FZERO;
		fv++;
	}
	u.u_procp->p_flag |= SPTECHG;
#endif
}

munmapfd(fd)
{
#ifdef sun
	register struct fpte *pte;
	register int i;

	for (i = 0; i < u.u_dsize; i++) {
		pte = (struct fpte *)dptopte(u.u_procp, i);
		if (pte->pg_v && pte->pg_fod && pte->pg_fileno == fd) {
			*(int *)pte = (PG_UW|PG_FOD);
			pte->pg_fileno = PG_FZERO;
		}
	}
#endif
	u.u_pofile[fd] &= ~UF_MAPPED;
	
}

mprotect()
{

}

madvise()
{

}

mincore()
{

}

/* BEGIN DEFUNCT */
#ifdef s32
obreak()
{
	struct a {
		char	*nsiz;
	};
	breakcomm(((struct a *)u.u_ap)->nsiz);
}
breakcomm(nsiz)
   char *nsiz;
{
	register int n, d;

	/*
	 * set n to new data size
	 * set d to new-old
	 */

	/* Note that tsize is already segment rounded */
	n = btoc(nsiz) - u.u_tsize - LOWPAGES;
	if (n < 0)
		n = 0;
	d = clrnd(n - u.u_dsize);
	if (ctob(u.u_dsize+d) > u.u_rlimit[RLIMIT_DATA].rlim_cur) {
		DODEBUG (D_VMEM, ("ctob(u.u_dsize+d)=(0x%x) > u.u_rlimit[RLIMIT_DATA].rlim_cur=0x%x\n",
		ctob(u.u_dsize+d), u.u_rlimit[RLIMIT_DATA].rlim_cur));
		u.u_error = ENOMEM;
		return;
	}
	if (chksize((u_int)u.u_tsize, (u_int)u.u_dsize+d, (u_int)u.u_ssize))
		return;
	if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0)
		return;
	expand(d, 0);
}
/*
 * Set up the process' map so that a particular
 * set of physical pages are mapped into the
 * data area at a particular virtual address.
 * Note that all arguments must be multiples of
 * NBPG.
 */
#ifdef s32
fillphys(p, vaddr, paddr, size, pteFlag)
   register struct proc *p;	/* The only time when p will not be u.u_procp
				 * is when we are mapping the SKY board into a
				 * child process.
				 */
   char	*vaddr;
   char	*paddr;
   int	size;
   int	pteFlag;		/* V_NONCACHED	 ==> don't cache the page */
				/* V_MBIO	 ==> map page as mbio	  */

#else s32
fillphys(vaddr, paddr, size)
   char	*vaddr;
   char	*paddr;
   int	size;
#endif s32
{
	register int		ppage, vpage, count;
	register struct fpte	*fpte;

	if (((u_long)vaddr & pagemask) || ((u_long)paddr & pagemask) ||
	    ((u_long)size & pagemask)) {
		u.u_error = EFAULT;
		return;
	}
	ppage = btop(paddr);
	vpage = btop(vaddr);
	count = btop(size);
#ifdef s32
	/*
	 * If the pages are not in the upper 64K of
	 * memory then grow the data area to include
	 * them.
	 */
#endif s32
	if ((vpage >> PAGE_TO_SEG_SHIFT) != nsegs(p)-1 &&
#ifdef s32
	    vtodp(p, vpage + count) > u.u_dsize)
#else s32
	    vtodp(u.u_procp, vpage + count) > u.u_dsize)
#endif s32
		breakcomm(vaddr+size);
	if (u.u_error)
		return;
	if (!useracc(vaddr, size, B_WRITE)) {
		u.u_error = EFAULT;
		return;
	}
#ifdef s32
	fpte = (struct fpte *)vtopte(p, vpage);
#else s32
	fpte = (struct fpte *)vtopte(u.u_procp, vpage);
#endif s32
	while (count--) {
		/*
		 * Only map in over the pages in the
		 * upper 64K of memory, zero fill pages,
		 * or pages already fillphys'd.
		 */
		if ((vpage >> PAGE_TO_SEG_SHIFT) != nsegs(p)-1 &&
		       (fpte->pg_fod == 0 || (fpte->pg_fileno != PG_FZERO &&
					      fpte->pg_fileno != PG_FPHYS))) {
			u.u_error = EFAULT;
			return;
		}
		DODEBUG(D_VMEM,("fillphys: vpage 0x%x, ppage 0x%x\n", vpage, ppage));
		fpte->pg_fod = 1;
#ifdef	M68020
		/*
		 * Non-cached pages are strictly pg_fod==1, pg_fileno==FPHYS.
		 * Vis-a-vis sureg(), they may only reside as a "DATAENTRY"
		 * or as a "TOPENTRY" in the programs's address space.
		 */
		fpte->pg_noncached = (pteFlag & V_NONCACHED) ? 1 : 0;
#endif	M68020

		fpte->pg_fileno = PG_FPHYS;
		fpte->pg_blkno  = ppage++;

		if (pteFlag & V_MBIO) {
			/*
			 * We would like to be able
			 * to map pages
			 *    ((struct pte *) fpte)->pg_space==PGSP_MBIO
			 * into a user's address space.
			 * We can't because THESE PTE's are strictly
			 * (struct fpte *) fill-on-demand pte's.
			 * So we ingraciously overload the semantics
			 * of the pg_blkno subfield with a designation
			 * of the intended i/o-ness of the page!
			 *
			 * Pte-s for iospace pages are constrained
			 * to only the fill-on-demand s/w pte format.
			 */
			fpte->pg_blkno  |= V_MBIO;
		}

		newptes(fpte++, vpage++, 1);
	}
}
#ifdef s32 /* LOCKPAGES */
/*
 * Lock some of this process' pages in
 * memory.  This means that the process
 * is not swappable and each of the pages
 * is not pageable.
 */
lockpages()
{
	register int vpage, count;
	register struct pte *pte;
	int s;
	struct a {
		char	*vaddr;
		int	size;
		int	locking;
	} *uap = (struct a *)u.u_ap;

	if (((u_long)uap->vaddr & pagemask) || ((u_long)uap->size & pagemask)) {
		u.u_error = EFAULT;
		return;
	}
	vpage = btop(uap->vaddr);
	count = btop(uap->size);
	if (!useracc(uap->vaddr, uap->size, B_WRITE)) {
		u.u_error = EFAULT;
		return;
	}
	pte = vtopte(u.u_procp, vpage);
	DODEBUG(D_VMEM,("user %slocking pid %d, vaddr 0x%x, ppages",
		(!uap->locking ? "un" : ""), u.u_procp->p_pid, uap->vaddr));
	s = spl5();
	if (uap->locking)
		u.u_procp->p_flag |= SULOCK;	/* Make sure we never swap */
	while (count--) {
		if (!uap->locking)
		{
			if (pte->pg_v)
				pte->pg_ulock = 0;
		}
		else
		{
			if (pte->pg_v)
				mlock(pte->pg_pfnum);
			else
				pagein(ctob(vpage), 1);	/* return it locked */
			pte->pg_ulock = 1;
			munlock(pte->pg_pfnum);
		}
		DODEBUG(D_VMEM,(" 0x%x", pte->pg_pfnum));
		++pte;
		++vpage;
	}
	if (!uap->locking)
	{
		pte = tptopte(u.u_procp, 0);
		count = suregp0lr;
		while (count--) {
			if (pte->pg_v && pte->pg_ulock)
				goto locked;
			++pte;
		}
		pte = sptopte(u.u_procp, 0);
		count = p1pages(u.u_procp) - suregp1lr - HIGHPAGES;
		while (count--) {
			if (pte->pg_v && pte->pg_ulock)
				goto locked;
			--pte;
		}
		u.u_procp->p_flag &= ~SULOCK;
	}
locked:
	splx(s);
	DODEBUG(D_VMEM,("\n"));
}
#endif s32 /* LOCKPAGES */
#else s32
obreak()
{
	struct a {
		char	*nsiz;
	};
	register int n, d;

	/*
	 * set n to new data size
	 * set d to new-old
	 */

	n = btoc(((struct a *)u.u_ap)->nsiz) - ctos(u.u_tsize) * stoc(1);
	if (n < 0)
		n = 0;
	d = clrnd(n - u.u_dsize);
	if (ctob(u.u_dsize+d) > u.u_rlimit[RLIMIT_DATA].rlim_cur) {
		u.u_error = ENOMEM;
		return;
	}
	if (chksize((u_int)u.u_tsize, (u_int)u.u_dsize+d, (u_int)u.u_ssize))
		return;
	if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0)
		return;
	expand(d, 0);
}
#endif s32

int	both;

ovadvise()
{
	register struct a {
		int	anom;
	} *uap;
	register struct proc *rp = u.u_procp;
	int oanom = rp->p_flag & SUANOM;
	register struct pte *pte;
	register struct cmap *c;
	register int i;

#ifdef lint
	both = 0;
#endif
	uap = (struct a *)u.u_ap;
	trace(TR_VADVISE, uap->anom, u.u_procp->p_pid);
	rp->p_flag &= ~(SSEQL|SUANOM);
	switch (uap->anom) {

	case VA_ANOM:
		rp->p_flag |= SUANOM;
		break;

	case VA_SEQL:
		rp->p_flag |= SSEQL;
		break;
	}
	if ((oanom && (rp->p_flag & SUANOM) == 0) || uap->anom == VA_FLUSH) {
		/*
		 * Invalidate all of the data-segment pages.
		 */
		for (i = 0; i < rp->p_dsize; i += CLSIZE) {
			pte = dptopte(rp, i);
			if (pte->pg_v) {
				c = &cmap[pgtocm(pte->pg_pfnum)];
				if (c->c_lock)
					continue;
				pte->pg_v = 0;
				if (anycl(pte, pg_m))
					pte->pg_m = 1;
				distcl(pte);
			}
		}
	}
	if (uap->anom == VA_FLUSH) {	/* invalidate all pages */
		/*
		 * Invalidate all of the stack-segment pages.
		 */
		for (i = 1; i < rp->p_ssize; i += CLSIZE) {
			pte = sptopte(rp, i);
			if (pte->pg_v) {
				c = &cmap[pgtocm(pte->pg_pfnum)];
				if (c->c_lock)
					continue;
				pte->pg_v = 0;
				if (anycl(pte, pg_m))
					pte->pg_m = 1;
				distcl(pte);
			}
		}
#ifdef s32
		if (rp->p_textp)
		/*
		 * Invalidate all of the text-segment pages.
		 */
		for (i = 0; i < rp->p_textp->x_size; i += CLSIZE) {
#else s32
		for (i = 0; i < rp->p_tsize; i += CLSIZE) {
#endif s32
			pte = tptopte(rp, i);
			if (pte->pg_v) {
				c = &cmap[pgtocm(pte->pg_pfnum)];
				if (c->c_lock)
					continue;
				pte->pg_v = 0;
				if (anycl(pte, pg_m))
					pte->pg_m = 1;
				distcl(pte);
				distpte(rp->p_textp, i, pte);
			}
		}
	}
#ifdef vax
	mtpr(TBIA, 0);
#endif
#ifdef s32
	/*
	 * Just about everything could have been
	 * touched so revalidate ALL user pages.
	 */
#ifdef USE_CTXT
	ctxt_invalidate(u.u_procp);
#endif USE_CTXT
	sureg();
#endif s32
}
/* END DEFUNCT */

/*
 * grow the stack to include the SP
 * true return if successful.
 */
grow(sp)
	unsigned sp;
{
	register int si;

#ifdef s32
	if (sp >= (unsigned)usrstack(u.u_procp)-ctob(u.u_ssize))
		/*
		 * Stack reference is to location contained
		 * in the stack area -- nothing to do -- return TRUE.
		 */
		return (1);

	si = clrnd(btoc(((unsigned)usrstack(u.u_procp)-sp)) - u.u_ssize +SINCR);
#else s32
	if (sp >= USRSTACK-ctob(u.u_ssize))
		return (0);
	si = clrnd(btoc((USRSTACK-sp)) - u.u_ssize + SINCR);
#endif s32
	if (ctob(u.u_ssize+si) > u.u_rlimit[RLIMIT_STACK].rlim_cur)
		return (0);
	if (chksize((u_int)u.u_tsize, (u_int)u.u_dsize, (u_int)u.u_ssize+si))
		return (0);
	if (swpexpand(u.u_dsize, u.u_ssize+si, &u.u_dmap, &u.u_smap)==0)
		return (0);
	
	expand(si, 1);
	return (1);
}
