static char rcsid[] = "$Header: vm_machdep.c,v 820.1 86/12/04 19:54:57 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.				*
*									*
************************************************************************/

/*	vm_machdep.c	5.3	82/12/17	*/

#include "../machine/pte.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/cmap.h"
#include "../h/mount.h"
#include "../h/vm.h"
#include "../h/vmmac.h"
#include "../h/text.h"
#ifdef s32
#include "../machine/cpu.h"
#include "../machine/context.h"
#include "../h/map.h"
#include "../h/seg.h"
#endif s32

#include "../s32/mtpr.h"

/*
 * Set a red zone in the kernel stack after the u. area.
 */
setredzone(pte, vaddr)
	register struct pte *pte;
	caddr_t vaddr;
{

#ifndef s32
	/*
	 * Won't work for s32 since our upage is
	 * a single page in length (UPAGES == 1).
	 */
	pte += (sizeof (struct user) + NBPG - 1) / NBPG;
	*(int *)pte &= ~PG_PROT;
	*(int *)pte |= PG_URKR;
	if (vaddr)
		mtpr(TBIS, vaddr + sizeof (struct user));
#endif !s32
}

#ifndef mapin
mapin(pte, v, pfnum, count, prot)
	struct pte *pte;
	u_int v, pfnum;
	int count, prot;
{
#ifdef s32
	register struct pte *lpte = pte;
	register int i = count;

	while (i-- > 0)
		*(int *)lpte++ = pfnum++ | prot;
	setsysmap(v, pte, count);
#else s32
	while (count > 0) {
		*(int *)pte++ = pfnum | prot;
		mtpr(TBIS, ptob(v));
		v++;
		pfnum++;
		count--;
	}
#endif s32
}
#endif

#ifdef notdef
/*ARGSUSED*/
mapout(pte, size)
	register struct pte *pte;
	int size;
{

	panic("mapout");
}
#endif

/*
 * Check for valid program size
 */
chksize(ts, ds, ss)
	size_t ts, ds, ss;
{
	static int maxdmap = 0;

#ifdef s32
	/*
	 * If the user has locked some pages in memory
	 * then we cannot allow him to call ptexpand.
	 */
	if ((u.u_procp->p_flag & SULOCK) &&
	    (ts+ds+ss+NPTEPG-1)/NPTEPG > u.u_procp->p_szpt) {
		u.u_error = EBUSY;
		return(1);
	}
#endif s32
	if (ts>MAXTSIZ || ds>MAXDSIZ || ss>MAXSSIZ) {
		u.u_error = ENOMEM;
		return(1);
	}
	/* check for swap map overflow */
	if (maxdmap == 0) {
		register int i, blk;

		blk = dmmin;
		for (i = 0; i < NDMAP; i++) {
			maxdmap += blk;
			if (blk < dmmax)
				blk *= 2;
		}
	}
	if (ctod(ts) > NXDAD * dmtext ||
	    ctod(ds) > maxdmap || ctod(ss) > maxdmap) {
		u.u_error = ENOMEM;
		return (1);
	}
	/*
	 * Make sure the process isn't bigger than our
	 * virtual memory limit.
	 *
	 * THERE SHOULD BE A CONSTANT FOR THIS.
	 */
#ifdef s32
	/*
	 * Virtual memory limit depends upon
	 * which address space we are inhabititing.
	 */
	if (ptos(usrbase) + ctos(ts) + ctos(ds) + ctos(ss) > ptos(usrtop(u.u_procp))) {
#else s32
	if (ts + ds + ss + LOWPAGES + HIGHPAGES > btoc(USRSTACK)) {
#endif s32
		u.u_error = ENOMEM;
		return (1);
	}
	return (0);
}
/*
 * Copy the user's page table entries
 * to the hardware.
 *
 * NOTE: this must always be called with
 * user virtual addresses.
 */
newptes(pte, vpage, count)
   struct pte *pte;
   u_int vpage;
   int count;
{
	setsysmap(vpage-btoc(USRTEXT)+LOWPAGES, pte, count);
}
/*
 * Change protection codes of text segment.
 * Have to flush translation buffer since this
 * affect virtual memory mapping of current process.
 */
chgprot(addr, tprot)
	caddr_t addr;
	long tprot;
{
	unsigned v;
	int tp;
	register struct pte *pte;
	register struct cmap *c;

	v = clbase(btop(addr));
	if (!isatsv(u.u_procp, v)) {
		u.u_error = EFAULT;
		return (0);
	}
	tp = vtotp(u.u_procp, v);
	pte = tptopte(u.u_procp, tp);
	if (pte->pg_fod == 0 && pte->pg_pfnum) {
		c = &cmap[pgtocm(pte->pg_pfnum)];
		if (c->c_blkno && c->c_mdev != MSWAPX)
			munhash(mount[c->c_mdev].m_dev,
			    (daddr_t)(u_long)c->c_blkno);
	}
	*(int *)pte &= ~PG_PROT;
	*(int *)pte |= tprot;
	distcl(pte);
#ifdef s32
	setsysmap(v, pte, 1);
	setsegmap(MYCTXT, addr,
			 (getsegmap(MYCTXT, addr) & ~SEG_ACCMODE) | (tprot == RO ? SEG_AUR : SEG_AURW));
#else s32
	tbiscl(v);
#endif s32
	return (1);
}
/*
 * Set the protection code for the
 * text segment.
 */
settprot(tprot)
   register long tprot;
{
	register long *ptaddr = (long *)getp0br();
	register int page = btoc(USRTEXT);
	register int count = u.u_tsize;
	register int seg = btos(USRTEXT);

	while (count--)
	{
		*ptaddr = (*ptaddr & ~PG_PROT) | tprot;
		/*
		 * We do not have to write these
		 * through since we only changed the
		 * protection (here, at least) and the
		 * page map does not contain protection.
		 *
		 * setsysmap(page++, ptaddr++, 1);
		 */
		++ptaddr;
	}
	/*
	 * We must set each segment of the text segment
	 * to the correct access mode, however.
	 */
	count = ptos(u.u_tsize);
	while (count--)
	{
		register u_short segno;

		/*
		 * We must not change protection for segments that are not
		 * mapped in!
		 */
		segno = getsegmap(MYCTXT, seg<<segshift) & ~SEG_ACCMODE;
		if ((segno & SEG_PAGE) == DUMMYSMAP) {
			++seg;
			continue;
		}
		setsegmap(MYCTXT, seg<<segshift,
				(segno) | (tprot == RO ? SEG_AUR : SEG_AURW));
		++seg;
	}
}

/*
 * Rest are machine-dependent
 */

getmemc(addr)
	caddr_t addr;
{
	register int c;
	struct pte savemap;

	savemap = mmap[0];
	*(int *)mmap = PG_V | PG_KR | btop(addr);
#ifdef s32
	setsysmap(btop(vmmap), mmap, 1);
	c = *(char *)&vmmap[(int)addr & PGOFSET];
	mmap[0] = savemap;
	setsysmap(btop(vmmap), mmap, 1);
#else s32
	mtpr(TBIS, vmmap);
	c = *(char *)&vmmap[(int)addr & PGOFSET];
	mmap[0] = savemap;
	mtpr(TBIS, vmmap);
#endif s32
	return (c & 0377);
}

putmemc(addr, val)
	caddr_t addr;
{
	struct pte savemap;

	savemap = mmap[0];
	*(int *)mmap = PG_V | PG_KW | btop(addr);
#ifdef s32
	setsysmap(btop(vmmap), mmap, 1);
	*(char *)&vmmap[(int)addr & PGOFSET] = val;
	mmap[0] = savemap;
	setsysmap(btop(vmmap), mmap, 1);
#else s32
	mtpr(TBIS, vmmap);
	*(char *)&vmmap[(int)addr & PGOFSET] = val;
	mmap[0] = savemap;
	mtpr(TBIS, vmmap);
#endif s32
}

/*
 * Move pages from one kernel virtual address to another.
 * Both addresses are assumed to reside in the Sysmap,
 * and size must be a multiple of CLSIZE.
 */
pagemove(from, to, size)
	register caddr_t from, to;
	int size;
{
	register struct pte *fpte, *tpte;

	/*
	 * Won't work with some of kernel virtual memory
	 * up in high memory.
	 */
	panic("pagemove 1");
	if (size % CLBYTES)
		panic("pagemove");
#ifdef s32
	fpte = &Sysmap[btop(from - (int)&Sysbase)];
	tpte = &Sysmap[btop(to - (int)&Sysbase)];
#else s32
	fpte = &Sysmap[btop(from - 0x80000000)];
	tpte = &Sysmap[btop(to - 0x80000000)];
#endif s32
	while (size > 0) {
#ifdef s32
		*tpte = *fpte;
		*(int *)fpte = 0;
		setsysmap(btop(from), fpte++, 1);
		setsysmap(btop(to), tpte++, 1);
#else s32
		*tpte++ = *fpte;
		*(int *)fpte++ = 0;
		mtpr(TBIS, from);
		mtpr(TBIS, to);
#endif s32
		from += NBPG;
		to += NBPG;
		size -= NBPG;
	}
}
