/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION  1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:vm_mem.c 12.0$ */
/* $ACIS:vm_mem.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/sys/RCS/vm_mem.c,v $ */

#if !defined(lint) && !defined(NO_RCS_HDRS)
static char *rcsid = "$Header:vm_mem.c 12.0$";
#endif

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

#ifdef ibm032
#include "../machine/debug.h"
#include "../machine/mmu.h"
#endif ibm032

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

#include "param.h"
#include "systm.h"
#include "cmap.h"
#include "dir.h"
#include "user.h"
#include "proc.h"
#include "text.h"
#include "vm.h"
#include "file.h"
#ifndef VFS
#include "inode.h"
#else !VFS
#include "../h/vfs.h"
#include "vnode.h"
#endif !VFS
#include "buf.h"
#ifndef VFS
#include "mount.h"
#endif !VFS
#include "trace.h"
#include "map.h"
#include "kernel.h"
#ifdef VFS
#include "../ufs/mount.h"
#endif VFS

#if defined(ibm032) && defined(DEBUG)
char cmdebug;	 /* added 9/84	for debugging */
#endif ibm032
/*
 * Allocate memory, and always succeed
 * by jolting page-out daemon
 * so as to obtain page frames.
 * To be used in conjunction with vmemfree().
 */
vmemall(pte, size, p, type)
	register struct pte *pte;
	int size;
	struct proc *p;
{
	register int m;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("vmemall,pte=%x->%x,size=%x,p=%x,type=%x\n",pte,*(unsigned *)pte,size,p,type);
#endif ibm032
	if (size <= 0 || size > maxmem)
		panic("vmemall size");
	while (size > 0) {
		if (freemem < desfree)
			outofmem();
		while (freemem == 0)
			sleep((caddr_t)&freemem, PSWP+2);
		m = imin(size, freemem);
		/* (void) memall(pte, m, p, type);*/
		/* Is this the cause of the panics? */
		/* See similar one in pagein in vm_page.c */
		if (memall(pte, m, p, type) == 0)
			printf("vmemall: lost the memall race; possible bug\n");
		size -= m;
		pte += m;
	}
	if (freemem < desfree)
		outofmem();
	/*
	 * Always succeeds, but return success for
	 * vgetu and vgetpt (e.g.) which call either
	 * memall or vmemall depending on context.
	 */
	return (1);
}

/*
 * Free valid and reclaimable page frames belonging to the
 * count pages starting at pte.  If a page is valid
 * or reclaimable and locked (but not a system page), then
 * we simply mark the page as c_gone and let the pageout
 * daemon free the page when it is through with it.
 * If a page is reclaimable, and already in the free list, then
 * we mark the page as c_gone, and (of course) don't free it.
 *
 * Determines the largest contiguous cluster of
 * valid pages and frees them in one call to memfree.
 */
vmemfree(pte, count)
	register struct pte *pte;
	register int count;
{
	register struct cmap *c;
	register struct pte *spte;
	register int j;
	int size, pcnt;
#ifdef notdef
	int fileno;
#endif

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("vmemfree, pte=%x->%x, count=%x\n",pte,*(unsigned *)pte,count);
#endif ibm032
	if (count % CLSIZE)
		panic("vmemfree");
	for (size = 0, pcnt = 0; count > 0; pte += CLSIZE, count -= CLSIZE) {
		if (pte->pg_fod == 0 && pte->pg_pfnum) {
			c = &cmap[pgtocm(pte->pg_pfnum)];
			pcnt += CLSIZE;
			if (c->c_lock && c->c_type != CSYS) {
				for (j = 0; j < CLSIZE; j++)
					*(int *)(pte+j) &= PG_PROT;
				c->c_gone = 1;
				goto free;
			}
			if (c->c_free) {
				pcnt -= CLSIZE;
				for (j = 0; j < CLSIZE; j++)
					*(int *)(pte+j) &= PG_PROT;
				if (c->c_type == CTEXT)
					distpte(&text[c->c_ndx], (int)c->c_page,
					    pte);
				c->c_gone = 1;
				goto free;
			}
			if (size == 0)
				spte = pte;
			size += CLSIZE;
			continue;
		}
#ifdef notdef
		/* Don't do anything with mapped ptes */
		if (pte->pg_fod && pte->pg_v)
			goto free;
#endif
		if (pte->pg_fod) {
#ifdef notdef
			fileno = ((struct fpte *)pte)->pg_fileno;
			if (fileno < NOFILE)
				panic("vmemfree vread");
#endif
			for (j = 0; j < CLSIZE; j++)
				*(int *)(pte+j) &= PG_PROT;
		}
free:
		if (size) {
			memfree(spte, size, 1);
			size = 0;
		}
	}
	if (size)
		memfree(spte, size, 1);
	return (pcnt);
}

/*
 * Unlink a page frame from the free list -
 *
 * Performed if the page being reclaimed
 * is in the free list.
 */
munlink(c)
	register struct cmap *c;
{
	register int next, prev;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("munlink: c=%x\n",c);
#endif ibm032
	next = c->c_next;
	prev = c->c_prev;
	cmap[prev].c_next = next;
	cmap[next].c_prev = prev;
	c->c_free = 0;
	if (freemem < minfree)
		outofmem();
	freemem -= CLSIZE;
}

/*
 * Allocate memory -
 *
 * The free list appears as a doubly linked list
 * in the core map with cmap[0] serving as a header.
 */
memall(pte, size, p, type)
	register struct pte *pte;
	int size;
	struct proc *p;
{
	register struct cmap *c;
	register struct pte *rpte;
	register struct proc *rp;
#ifdef ibm032
	register struct hatipt_entry *ipte;
	unsigned sid;
#endif ibm032
	register int curpos;
	register int i, j, next;
	unsigned pf;
	struct cmap *c1, *c2;
	int s;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("memall(pte 0x%x -> 0x%x, size=%d, pid=%d, type=%d)",
			pte, *(unsigned *)pte, size, p->p_pid, type);
#endif ibm032
	if (size % CLSIZE)
		panic("memall");
	s = splimp();
	if (size > freemem) {
		splx(s);
		return (0);
	}
#if defined(ibm032) && defined(DEBUG)
	if(cmdebug)
		iscmapok();
#endif ibm032
	trace(TR_MALL, size, u.u_procp->p_pid);
	/* loop allocating one click at a time */
	for (i = size; i > 0; i -= CLSIZE) {
	/* point to the current	cluster */
		curpos = cmap[CMHEAD].c_next;
		c = &cmap[curpos];
		freemem -= CLSIZE;
		next = c->c_next;
#ifdef ibm032
		/* unlink that cluster */
#endif ibm032
		cmap[CMHEAD].c_next = next;
		cmap[next].c_prev = CMHEAD;
		if (c->c_free == 0)
			panic("dup mem alloc");
#ifndef ibm032
		if (cmtopg(curpos) > maxfree)
#else ibm032
		pf = cmtopg(curpos);
		if (pf > maxfree)
#endif ibm032
			panic("bad mem alloc");
#ifndef ibm032
		if (c->c_gone == 0 && c->c_type != CSYS) {
#else ibm032
		/* clear out any previous mapping */
		if (c->c_gone == 0)
			if (c->c_type == CSYS)
				mapout(&pf, CLSIZE);
					/* note: using pf as a pte */
			else {
#endif ibm032
			if (c->c_type == CTEXT)
				rp = text[c->c_ndx].x_caddr;
			else
				rp = &proc[c->c_ndx];
			while (rp->p_flag & SNOVM)
				rp = rp->p_xlink;
			switch (c->c_type) {

			case CTEXT:
				rpte = tptopte(rp, c->c_page);
				break;
			case CDATA:
				rpte = dptopte(rp, c->c_page);
				break;
			case CSTACK:
				rpte = sptopte(rp, c->c_page);
				break;
			}  /* switch */
#if defined(ibm032) && defined(DEBUG)
			if(vmdebug)
				printf("memall zapping pte 0x%x -> 0x%x\n",
						rpte, *(unsigned *)rpte);
#endif ibm032
#ifdef	ibm032
			set_refmod_bits(rpte->pg_pfnum, 0, 0);
#endif
			zapcl(rpte, pg_pfnum) = 0;
			if (c->c_type == CTEXT)
				distpte(&text[c->c_ndx], c->c_page, rpte);
		}  /* else */
		switch (type) {  /* which type do we want? */

		case CSYS:
			c->c_ndx = p->p_ndx;
#ifdef ibm032
			sid = MMU_SID_SYSTEM; /* kernel poopa */
#endif ibm032
			break;

		case CTEXT:
			c->c_page = vtotp(p, ptetov(p, pte));
#ifndef ibm032
			c->c_ndx = p->p_textp - &text[0];
#else ibm032
			c->c_ndx = p->p_textp - text;
			sid = make410sid( p->p_textp );
#endif ibm032
			break;

		case CDATA:
			c->c_page = vtodp(p, ptetov(p, pte));
			c->c_ndx = p->p_ndx;
#ifdef ibm032
			sid = p->p_tsize
                             ? makeUsid(p)     /* 410/413 data in P1 */
                             : make407sid(p);  /* 407 data in P0 */
#endif ibm032
			break;

		case CSTACK:
			c->c_page = vtosp(p, ptetov(p, pte));
			c->c_ndx = p->p_ndx;
#ifdef ibm032
			sid = makeUsid(p);      /* user stack in P1 */
#endif  ibm032
			break;
#ifdef ibm032

		case CUSTRUCT:
                       c->c_ndx = p->p_ndx;
                       sid = makeUsid(p);      /* upages in P1 */
			break;
#endif ibm032
		}
		/* if on disk, point to	it */
		if (c->c_blkno) {
			/*
			 * This is very like munhash(), except
			 * that we really don't want to bother
#ifndef VFS
			 * to calculate a dev to pass to it.
#else !VFS
			 * to calculate a vp to pass to it.
#endif !VFS
			 */
			j = CMHASH(c->c_blkno);
			c1 = &cmap[cmhash[j]];
			if (c1 == c)
				cmhash[j] = c1->c_hlink;
			else {
				for (;;) {
					if (c1 == ecmap)
						panic("memall ecmap");
					c2 = c1;
					c1 = &cmap[c2->c_hlink];
					if (c1 == c)
						break;
				}
				c2->c_hlink = c1->c_hlink;
			}
#ifndef VFS
			if (mfind(c->c_mdev == MSWAPX ?
			      swapdev : mount[c->c_mdev].m_dev,
			      (daddr_t)(u_long)c->c_blkno))
#else !VFS
			if (mfind(c->c_vp, c->c_blkno))
#endif !VFS
				panic("memall mfind");
#ifndef VFS
			c1->c_mdev = 0;
#else !VFS
			VN_RELE(c1->c_vp);
			c1->c_vp = (struct vnode *)0;
#endif !VFS
			c1->c_blkno = 0;
			c1->c_hlink = 0;
		}
#ifndef ibm032
		pf = cmtopg(curpos);
		for (j = 0; j < CLSIZE; j++)
			*(int *)pte++ = pf++;
#else ibm032
		/* map in all the pages	in this click */
		ipte = &MMU_HATIPT[pf];
#ifdef DEBUG
		if (vmdebug)
			printf("sid=%x,ipte=%x\n", sid,ipte);
#endif DEBUG
#if CLSIZE != 1
		for (j = 0; j < CLSIZE; j++)
#endif
		{
#ifdef DEBUG
			if (ipte->ipt_ptr != MMU_UNDEF_PTR) {  /* debug */
				printf("memall:	page 0x%x %x =	%x %x %x %x\n", pf, ipte,
					*(int *)(ipte), *(int *)(ipte+4),
					*(int *)(ipte+8), *(int	*)(ipte+12) );
				panic("alloc hot page");
			}
#endif DEBUG
			(*ipte).key_addrtag = sid << MMU_VPAGE_BITS;
			*(int *)pte++ = pf++;
		}
#endif ibm032
		c->c_free = 0;
		c->c_gone = 0;
		if (c->c_intrans || c->c_want)
			panic("memall intrans or want");
		c->c_lock = 1;
		c->c_type = type;
	}
	splx(s);
	return (size);
}

/*
 * Free memory -
 *
 * The page frames being returned are inserted
 * to the head/tail of the free list depending
 * on whether there is any possible future use of them.
 *
 * If the freemem count had been zero,
 * the processes sleeping for memory
 * are awakened.
 */
memfree(pte, size, detach)
	register struct pte *pte;
	register int size;
{
#ifndef ibm032
	register int i, j, prev, next;
#else ibm032
	register int i, prev, next;
#endif ibm032
	register struct cmap *c;
	int s;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug) printf("memfree( pte 0x%x -> 0x%x,	size=%d, detach=%d )\n",
			     pte, *(unsigned *)pte, size, detach);
#endif ibm032
	if (size % CLSIZE)
		panic("memfree");
	if (freemem < CLSIZE * KLMAX)
		wakeup((caddr_t)&freemem);
	while (size > 0) {
		size -= CLSIZE;
		i = pte->pg_pfnum;
		if (i < firstfree || i > maxfree)
			panic("bad mem free");
		i = pgtocm(i);
		c = &cmap[i];
		if (c->c_free)
			panic("dup mem free");
#ifdef ibm032

		if (c->c_type != CSYS && c->c_mapped)
			mapout(pte, CLSIZE);

#endif ibm032
		if (detach && c->c_type != CSYS) {
#if CLSIZE == 1
			*(int *)(pte) &= PG_PROT;
#else
			for (j = 0; j < CLSIZE; j++)
				*(int *)(pte+j) &= PG_PROT;
#endif CLSIZE == 1
			c->c_gone = 1;
		}
		s = splimp();
		if (detach && c->c_blkno == 0) {
			next = cmap[CMHEAD].c_next;
			cmap[next].c_prev = i;
			c->c_prev = CMHEAD;
			c->c_next = next;
			cmap[CMHEAD].c_next = i;
		} else {
			prev = cmap[CMHEAD].c_prev;
			cmap[prev].c_next = i;
			c->c_next = CMHEAD;
			c->c_prev = prev;
			cmap[CMHEAD].c_prev = i;
		}
		c->c_free = 1;
		freemem += CLSIZE;
		splx(s);
		pte += CLSIZE;
	}
#if defined(ibm032) && defined(DEBUG)
	if(cmdebug)
		iscmapok();
#endif ibm032
}

/*
 * Allocate wired-down (non-paged) pages in kernel virtual memory.
 */
caddr_t
wmemall(pmemall, n)
	int (*pmemall)(), n;
{
	register int npg;
	register caddr_t va;
	register int a;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("wmemall: pmemall=%x, n=%x\n",pmemall,n);
#endif ibm032
	npg = clrnd(btoc(n));
	a = rmalloc(kernelmap, (long)npg);
	if (a == 0)
		return (0);
	if ((*pmemall)(&Usrptmap[a], npg, &proc[0], CSYS) == 0) {
		rmfree(kernelmap, (long)npg, (long)a);
		return (0);
	}
	va = (caddr_t) kmxtob(a);
	vmaccess(&Usrptmap[a], va, npg);
	return (va);
}

/*
 * Allocate wired-down (non-paged) pages in kernel virtual memory.
 * (and clear them)
 */
caddr_t
zmemall(pmemall, n)
	int (*pmemall)(), n;
{
	register int npg;
	register caddr_t va;
	register int a;

#if defined(ibm032) && defined(DEBUG)
	if(vmdebug)
		printf("zmemall: pmemall=%x,n=%x\n",pmemall,n);
#endif ibm032
	npg = clrnd(btoc(n));
	a = rmalloc(kernelmap, (long)npg);
	if (a == 0)
		return (0);
	if ((*pmemall)(&Usrptmap[a], npg, &proc[0], CSYS) == 0) {
		rmfree(kernelmap, (long)npg, (long)a);
		return (0);
	}
	va = (caddr_t) kmxtob(a);
	vmaccess(&Usrptmap[a], va, npg);
	while (--npg >= 0)
		clearseg((unsigned)(PG_PFNUM & *(int *)&Usrptmap[a++]));
	return (va);
}

wmemfree(va, n)
	caddr_t va;
	int n;
{
	register int a, npg;

#if defined(ibm032) && defined(DEBUG)
	if (vmdebug)
		printf("wmemfree: va=%x,n=%x\n",va,n);
#endif ibm032
	a = btokmx((struct pte *) va);
	npg = clrnd(btoc(n));
		(void) memfree(&Usrptmap[a], npg, 0);
	rmfree(kernelmap, (long)npg, (long)a);
}

/*
 * Enter clist block c on the hash chains.
#ifndef VFS
 * It contains file system block bn from device dev.
 * Dev must either be a mounted file system or the swap device
 * so we panic if getfsx() cannot find it.
#else !VFS
 * It contains file system block bn from vnode vp.
#endif !VFS
 */
#ifndef VFS
mhash(c, dev, bn)
#else !VFS
mhash(c, vp, bn)
#endif !VFS
	register struct cmap *c;
#ifndef VFS
	dev_t dev;
#else !VFS
	struct vnode *vp;
#endif !VFS
	daddr_t bn;
{
	register int i = CMHASH(bn);

	c->c_hlink = cmhash[i];
	cmhash[i] = c - cmap;
	c->c_blkno = bn;
#ifndef VFS
	i = getfsx(dev);
	if (i == -1)
		panic("mhash");
	c->c_mdev = i;
#else !VFS
	c->c_vp = vp;
	VN_HOLD(vp);
#endif !VFS
}

/*
#ifndef VFS
 * Pull the clist entry of <dev,bn> off the hash chains.
#else !VFS
 * Pull the clist entry of <vp,bn> off the hash chains.
#endif !VFS
 * We have checked before calling (using mfind) that the
 * entry really needs to be unhashed, so panic if we can't
 * find it (can't happen).
 * Must be called at splimp.
 */
#ifndef VFS
munhash(dev, bn)
	dev_t dev;
#else !VFS
munhash(vp, bn)
	register struct vnode *vp;
#endif !VFS
	daddr_t bn;
{
	register int i = CMHASH(bn);
	register struct cmap *c1, *c2;

	c1 = &cmap[cmhash[i]];
	if (c1 == ecmap)
		panic("munhash");
#ifndef VFS
	if (c1->c_blkno == bn && getfsx(dev) == c1->c_mdev)
#else !VFS
	if (c1->c_blkno == bn && c1->c_vp == vp)
#endif !VFS
		cmhash[i] = c1->c_hlink;
	else {
		for (;;) {
			c2 = c1;
			c1 = &cmap[c2->c_hlink];
			if (c1 == ecmap)
				panic("munhash");
#ifndef VFS
			if (c1->c_blkno == bn && getfsx(dev) == c1->c_mdev)
#else !VFS
			if (c1->c_blkno == bn && c1->c_vp == vp)
#endif !VFS
				break;
		}
		c2->c_hlink = c1->c_hlink;
	}
#ifndef VFS
	if (mfind(dev, bn))
#else !VFS
	if (mfind(vp, bn))
#endif !VFS
		panic("munhash mfind");
#ifndef VFS
	c1->c_mdev = 0;
#else !VFS
	VN_RELE(vp);
	c1->c_vp = (struct vnode *)0;
#endif !VFS
	c1->c_blkno = 0;
	c1->c_hlink = 0;
}

/*
#ifndef VFS
 * Look for block bn of device dev in the free pool.
#else !VFS
 * Look for block bn of vnode vp in the free pool.
#endif !VFS
 * Currently it should not be possible to find it unless it is
 * c_free and c_gone, although this may later not be true.
 * (This is because active texts are locked against file system
 * writes by the system.)
 */
struct cmap *
#ifndef VFS
mfind(dev, bn)
	register dev_t dev;
#else !VFS
mfind(vp, bn)
	register struct vnode *vp;
#endif !VFS
	register daddr_t bn;
{
	register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]];
	register int si = splimp();
	register struct cmap *ec = ecmap;

	while (c1 != ec) {
#ifndef VFS
		if (c1->c_blkno == bn && c1->c_mdev == getfsx(dev)) {
#else !VFS
		if (c1->c_blkno == bn && c1->c_vp == vp) {
#endif !VFS
			splx(si);
			return (c1);
		}
		c1 = &cmap[c1->c_hlink];
	}
	splx(si);
	return ((struct cmap *)0);
}

/*
#ifndef VFS
 * Purge blocks from device dev from incore cache
 * before umount().
#else !VFS
 * Purge blocks from vnode vp from incore cache
#endif !VFS
 */
#ifndef VFS
mpurge(mdev)
	int mdev;
#else !VFS
mpurge(vp)
	register struct vnode *vp;
#endif !VFS
{
	register struct cmap *c1, *c2;
	register int i;
	int si = splimp();
#ifdef VFS
	int j = 0;
#endif VFS

	for (i = 0; i < CMHSIZ; i++) {
more:
		c1 = &cmap[cmhash[i]];
		if (c1 == ecmap)
			continue;
#ifndef VFS
		if (c1->c_mdev == mdev)
#else !VFS
		if (c1->c_vp == vp)
#endif !VFS
			cmhash[i] = c1->c_hlink;
		else {
			for (;;) {
				c2 = c1;
				c1 = &cmap[c1->c_hlink];
				if (c1 == ecmap)
					goto cont;
#ifndef VFS
				if (c1->c_mdev == mdev)
#else !VFS
				if (c1->c_vp == vp)
#endif !VFS
					break;
			}
			c2->c_hlink = c1->c_hlink;
		}
#ifndef VFS
		c1->c_mdev = 0;
#else !VFS
		j++;
		c1->c_vp = (struct vnode *)0;
#endif !VFS
		c1->c_blkno = 0;
		c1->c_hlink = 0;
		goto more;
cont:
		;
	}
	splx(si);
#ifdef VFS
	while (j--)
		VN_RELE(vp);
#endif VFS
}

#ifdef VFS
/*
 * Purge blocks from filesystem vfsp from incore cache
 * before umount().
 */
mpurgevfs(vfsp)
	register struct vfs *vfsp;
{
	register struct cmap *c1, *c2;
	register int i;
	int si = splimp();

more:
	for (i = 0; i < CMHSIZ; i++) {
		c1 = &cmap[cmhash[i]];
		if (c1 == ecmap)
			continue;
		if (c1->c_vp->v_vfsp == vfsp)
			cmhash[i] = c1->c_hlink;
		else {
			for (;;) {
				c2 = c1;
				c1 = &cmap[c1->c_hlink];
				if (c1 == ecmap)
					goto cont;
				if (c1->c_vp->v_vfsp == vfsp)
					break;
			}
			c2->c_hlink = c1->c_hlink;
		}
		(void) splx(si);
		VN_RELE(c1->c_vp);
		si = splimp();
		c1->c_vp = (struct vnode *)0;
		c1->c_blkno = 0;
		c1->c_hlink = 0;
		goto more;
cont:
		;
	}
	(void) splx(si);
}

#endif VFS
/*
 * Initialize core map
 */
meminit(first, last)
	int first, last;
{
	register int i;
	register struct cmap *c;
	register int prev;

#ifdef ibm032
	DEBUGF(vmdebug, printf("meminit: first=%x,last=%x\n",first,last));
	DEBUGF(vmdebug, printf("meminit: holestart=%x,holelength=%x\n",holestart,holelength));
#endif ibm032
	firstfree = clrnd(first);
	maxfree = clrnd(last - (CLSIZE - 1));
	freemem = maxfree - firstfree;
	ecmx = ecmap - cmap;
	if (ecmx < freemem / CLSIZE)
		freemem = ecmx * CLSIZE;
	prev = 0;
	for (i = 1; i <= freemem / CLSIZE; i++) {
#ifdef ibm032
		unsigned temp_pte;    /* note: used as a pte */
		/* unlink that real page from hatipt */
		temp_pte = firstfree+i-1;
		if (ishole(temp_pte)) {
			DEBUGF(vmdebug, printf("meminit: cmap[%d] hole\n",i));
			c = &cmap[i];
			c->c_type = CSYS;
			c->c_free = 0;
			continue;	/* do not put into free list */
		}
#if (defined(ATR) || defined(DEBUG)) && !(defined(SIM_REF_BIT) || defined(SIM_CHG_BIT))
	/*
	 * test to see if the reference/change bits work properly
	 * 1. make sure we can set/change the bits explictly
	 * 2. make sure that ref/chg memory references set the bits
	 */
		{
			int x;
			int err = 0;
			static int errcnt = 0;
			set_refmod_bits(temp_pte, 0, 0);
			if (get_mod_bit(temp_pte))
				err |= 1;
			if (get_ref_bit(temp_pte))
				err |= 2;
			set_refmod_bits(temp_pte, 1, 1);
			if (!get_mod_bit(temp_pte))
				err |= 4;
			if (!get_ref_bit(temp_pte))
				err |= 8;
			set_refmod_bits(temp_pte, 0, 0);
			x = * (int *) (SYSBASE + ptob(temp_pte));
			if (!get_ref_bit(temp_pte))
				err |= 16;
			* (int *) (SYSBASE + ptob(temp_pte)) = x;
			if (!get_mod_bit(temp_pte))
				err |= 32;
			set_refmod_bits(temp_pte, 0, 0);
			if (err && ((padebug&0x80000000) || ++errcnt <= 25))
				printf("page %x: ref/chg err=%b%s\n",temp_pte,err,
				"\20\1MOD=1\2REF=1\3MOD=0\4REF=0\5BAD-REF\6BAD-MOD",
				errcnt == 25 ? " -> Replace Processor Card!" : "");
		}

#endif DEBUG
		mapout((struct pte *)&temp_pte,1); /* link this page as free */
#endif ibm032
		cmap[prev].c_next = i;
		c = &cmap[i];
		c->c_prev = prev;
		c->c_free = 1;
		c->c_gone = 1;
		c->c_type = CSYS;
#ifndef VFS
		c->c_mdev = 0;
#else !VFS
		c->c_vp = (struct vnode *)0;
#endif !VFS
		c->c_blkno = 0;
		prev = i;
	}
	cmap[freemem / CLSIZE].c_next = CMHEAD;
	for (i = 0; i < CMHSIZ; i++)
		cmhash[i] = ecmx;
	cmap[CMHEAD].c_prev = freemem / CLSIZE;
	cmap[CMHEAD].c_type = CSYS;
	freemem -= holelength;			/* XXX fix later for overlap */
	avefree = freemem;
}

#ifdef notdef
/*
 * Wait for frame pf to become unlocked
 * if it is currently locked.
 */
mwait(c)
	struct cmap *c;
{

	mlock(c);
	munlock(c);
}

/*
 * Lock a page frame.
 */
mlock(c)
	register struct cmap *c;
{

#if defined(ibm032) && defined(DEBUG)
	if(vmdebug)
		printf("mlock: c=%x\n",c);
#endif ibm032
	while (c->c_lock) {
		c->c_want = 1;
		sleep((caddr_t)c, PSWP+1);
	}
	c->c_lock = 1;
}

/*
 * Unlock a page frame.
 */
munlock(c)
	register struct cmap *c;
{

#if defined(ibm032) && defined(DEBUG)
	if(vmdebug)
		printf("munlock: c=%x\n",c);
#endif ibm032
	if (c->c_lock == 0)
		panic("dup page unlock");
	if (c->c_want) {
		wakeup((caddr_t)c);
		c->c_want = 0;
	}
	c->c_lock = 0;
}
#endif notdef

/*
 * Lock a virtual segment.
 *
 * For each cluster of pages, if the cluster is not valid,
 * touch it to fault it in, otherwise just lock page frame.
 * Called from physio to ensure that the pages
 * participating in raw i/o are valid and locked.
 */
vslock(base, count)
	caddr_t base;
{
	register unsigned v;
	register int npf;
	register struct pte *pte;
	register struct cmap *c;

	v = btop(base);
	pte = vtopte(u.u_procp, v);
	npf = btoc(count + ((int)base & CLOFSET));
	while (npf > 0) {
		if (pte->pg_v) {
			c = &cmap[pgtocm(pte->pg_pfnum)];
			if (c->c_lock) {
				MLOCK(c);
				MUNLOCK(c);
				continue;
			}
			MLOCK(c);
		} else {
			pagein(ctob(v), 1);	/* return it locked */
		}
		pte += CLSIZE;
		v += CLSIZE;
		npf -= CLSIZE;
	}
}

/*
 * Unlock a virtual segment.
 */
vsunlock(base, count, rw)
	caddr_t base;
{
	register struct pte *pte;
	register int npf;
	register struct cmap *c;

	pte = vtopte(u.u_procp, btop(base));
	npf = btoc(count + ((int)base & CLOFSET));
	while (npf > 0) {
		c = &cmap[pgtocm(pte->pg_pfnum)];
		MUNLOCK(c);
		if (rw == B_READ)	/* Reading from device writes memory */
#ifndef ibm032
			pte->pg_m = 1;
#else ibm032
		{
			pte->pg_m = 1;
#ifdef SIM_CHG_BIT
			chg_mod_bit(pte, base);		/* remember it changed */
			base += NBPG * CLSIZE;
#endif SIM_CHG_BIT
			set_mod_bit(pte->pg_pfnum,1);
		}
#endif ibm032
		pte += CLSIZE;
		npf -= CLSIZE;
	}
}
#if defined(ibm032) && defined(DEBUG)

iscmapok()  /* added 9/84 for debugging */
{
	register struct cmap *c, *c1st;
	int s = splimp();

	c1st = &cmap[CMHEAD];

	for (c = &cmap[c1st->c_next]; c	!= c1st; c = &cmap[c->c_next])
		if (c->c_free == 0) {
			printf("cmap[0x%x].c_free == 0 (at 0x%x);n", c-c1st, c);
			panic("cmap hosed");
		}
	splx(s);
}
#endif ibm032
