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

/************************************************************************
*									*
*				Copyright 1984				*
*			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_subr.c	6.1	83/07/29	*/

/*
 * History:
 * ========
 */
#include "../machine/pte.h"
#ifdef s32
#include "../machine/cpu.h"
#endif s32

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/vm.h"
#include "../h/proc.h"
#include "../h/cmap.h"
#include "../h/inode.h"
#include "../h/buf.h"
#include "../h/text.h"
#include "../h/fs.h"
#ifdef s32
#include "../h/map.h"	/* For PAGE_TO_SEG_SHIFT */
#endif s32


/*
 * Make uarea of process p addressible at kernel virtual
 * address uarea through sysmap locations starting at map.
 */
uaccess(p, map, uarea)
	register struct proc *p;
	struct pte *map;
	register struct user *uarea;
{
	register int i;
	register struct pte *mp = map;
	struct pte upage_pte[UPAGES];

#ifdef	COMPILERBUG
	bcopy (p->p_addr, upage_pte, UPAGES * sizeof *p->p_addr);
#endif	COMPILERBUG
	for (i = 0; i < UPAGES; i++) {
		*(int *)mp = 0;
#ifdef	COMPILERBUG
		mp->pg_pfnum = upage_pte[i].pg_pfnum;
#else	COMPILERBUG
		mp->pg_pfnum = p->p_addr[i].pg_pfnum;
#endif	COMPILERBUG
		mp++;
	}
	vmaccess(map, (caddr_t)uarea, UPAGES);
}

/*
 * Validate the kernel map for size ptes which
 * start at ppte in the sysmap, and which map
 * kernel virtual addresses starting with vaddr.
 */
vmaccess(ppte0, vaddr, size0)
	struct pte *ppte0;
	register caddr_t vaddr;
	int size0;
{
	register struct pte *ppte = ppte0;
	register int size = size0;

	while (size != 0) {
		mapin(ppte, btop(vaddr), (unsigned)(*(int *)ppte & PG_PFNUM), 1,
			(int)(PG_V|PG_KW));
		ppte++;
		vaddr += NBPG;
		--size;
	}
}

/* 
 * Convert a pte pointer to
 * a virtual page number.
 */
ptetov(p, pte)
	register struct proc *p;
	register struct pte *pte;
{

	if (isatpte(p, pte))
		return (tptov(p, ptetotp(p, pte)));
	else if (isadpte(p, pte))
		return (dptov(p, ptetodp(p, pte)));
	else
		return (sptov(p, ptetosp(p, pte)));
}

/*
 * Convert a virtual page 
 * number to a pte address.
 *
 * Returns:	1) Pointer to the requested pte;
 *		2) -1 if pte not anything we know about;
 *		3) 0, perhaps in certain other degenerate cases.
 */
struct pte *
vtopte(p, v)
	register struct proc *p;
	register unsigned v;
{

	if (isatsv(p, v))
		return (tptopte(p, vtotp(p, v)));
	else if (isadsv(p, v))
		return (dptopte(p, vtodp(p, v)));
#ifdef s32
	else if (isassv(p, v))
		return (sptopte(p, vtosp(p, v)));
#ifdef s32	/* MAPUPPER64K */
	else if ((v >> PAGE_TO_SEG_SHIFT) == nsegs(p)-1)
		return (p->p_p0br + p->p_szpt*NPTEPG - HIGHPAGES + (v & V_VPAGENO));
#endif s32	/* MAPUPPER64K */
	else
		/*
		 * This can happen from vmdup which is called with
		 * a zero size segment but which calls vtopte on the
		 * front of it anyway.  Just return something that
		 * will blow up if it is used.
		 */
		return((struct pte *)-1);
#else s32
	else
		return (sptopte(p, vtosp(p, v)));
#endif s32

}

#ifdef s32
/*
 * Return the type (CTEXT, CDATA, CSTACK) of a virtual page.
 */
vtotype(p, v)
	register struct proc *p;
	register unsigned v;
{

	     if (isatsv(p, v)) return (CTEXT);
	else if (isassv(p, v)) return (CSTACK);
	else if (isadsv(p, v)) return (CDATA);
	printf("vtotype: invalid virtual page number, pid=%d, page=0x%x\n",
		p->p_pid,v);
	panic("vtotype");

}
#endif s32

/*
 * Initialize the page tables for paging from an inode,
 * by scouring up the indirect blocks in order.
 * Corresponding area of memory should have been vmemfree()d
 * first or just created.
 */
vinifod(pte, fileno, ip, bfirst, count)
	register struct fpte *pte;
	int fileno;
	register struct inode *ip;
	daddr_t bfirst;
	size_t count;
{
	int blast = bfirst + howmany(count, CLSIZE);
	register int i, j;
	int bn;
	register struct fs *fs = ip->i_fs;
	int nclpbsize = fs->fs_bsize / CLBYTES;

	while (bfirst < blast) {
		i = bfirst % nclpbsize;
		bn = fsbtodb(fs, bmap(ip, bfirst / nclpbsize, B_READ, 0));
		for ( ; i < nclpbsize; i++) {
			pte->pg_fod = 1;
			pte->pg_fileno = fileno;
			if (u.u_error || bn < 0) {
				pte->pg_blkno = 0;
				pte->pg_fileno = PG_FZERO;
				cnt.v_nzfod += CLSIZE;
			} else {
				pte->pg_blkno = bn + btodb(i * CLBYTES);
				cnt.v_nexfod += CLSIZE;
			}
			for (j = 1; j < CLSIZE; j++)
				pte[j] = pte[0];
			pte += CLSIZE;
			bfirst++;
			if (bfirst == blast)
				break;
		}
	}
}
