/*
 * jam 850226
 */

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

extern char pcopyarea[];
extern struct pte Pcopymap[];

struct proc	*pcopy_locked;	/* Process whose page is mapped in */
u_long		pcopy_vbase;	/* Virtual base of page mapped in */

/*
 * Copy data into kernel data space from
 * a process' virtual address space.  The
 * pages MUST already be in memory.
 */
int
pcopyin(procp, from, to, nbytes)
   register struct proc *procp;
   register caddr_t from;
   register caddr_t to;
   register int nbytes;
{
	while (nbytes > 0)
	{
		register int count;

		count = pcopy_mapin(procp, from, nbytes);
		bcopy((caddr_t)pcopyarea + ((u_long)from & PGOFSET), to, count);
		from += count;
		to += count;
		nbytes -= count;
	}
	return(0);
}

/*
 * Copy data from kernel data space to
 * a process' virtual address space.  The
 * pages MUST already be in memory.
 */
int
pcopyout(procp, from, to, nbytes)
   register struct proc *procp;
   register caddr_t from;
   register caddr_t to;
   register int nbytes;
{
	while (nbytes > 0)
	{
		register int count = nbytes;

		count = pcopy_mapin(procp, to, nbytes);
		bcopy(from, (caddr_t)pcopyarea + ((u_long)to & PGOFSET), count);
		from += count;
		to += count;
		nbytes -= count;
	}
	return(0);
}

/*
 * Map the physical page, which is currently
 * mapped into the process' address space
 * at the given address, into pcopyarea so
 * that it may be accessed.  Return the
 * number of bytes (starting at the base
 * address) which have been mapped in.
 */
int
pcopy_mapin(procp, base, size)
   struct proc *procp;
   register caddr_t base;
   register int size;
{
	register int offset = (u_long)base & PGOFSET;
	register u_long vbase = (u_long)base & ~PGOFSET;

	/*
	 * If the process has been indicated to
	 * be locked and the virtual address is
	 * already mapped in then we do not have
	 * to do any more checking.
	 */
	if (procp != pcopy_locked)
		pcopy_locked = 0;
	if (procp != pcopy_locked || vbase != pcopy_vbase)
	{
		register int ppage;

		pcopy_vbase = vbase;

		/*
		 * Convert the virtual address into a
		 * physical page number.
		 */
		ppage = (u_long)pvtop(procp, base) >> PGSHIFT;

		/*
		 * If the page is not already mapped
		 * in then map it in.
		 */
		if (!Pcopymap->pg_v || Pcopymap->pg_pfnum != ppage)
		{
			Pcopymap->pg_prot = PG_KW;
			Pcopymap->pg_v = 1;
			Pcopymap->pg_pfnum = ppage;
			setsysmap((u_long)pcopyarea >> PGSHIFT, Pcopymap, 1);
		}
	}

	/*
	 * Trim the count so that it is no bigger
	 * than the number of bytes left on this
	 * page.
	 */
	if (size > NBPG - offset)
		size = NBPG - offset;
	return(size);
}

/*
 * Indicates that the particular process' map
 * is not going to change so that the cacheing
 * can be more efficient.  Note that if a different
 * process is mapped in then the lock is broken.
 */
pcopy_lock(procp)
   register struct proc *procp;
{
	if (pcopy_locked != procp)
	{
		pcopy_locked = procp;
		pcopy_vbase = PGOFSET;	/* "impossible" value */
	}
}

/*
 * Indicates that the particular process' map
 * is no longer guaranteed to NOT change.
 */
/*ARGSUSED*/
pcopy_unlock(procp)
   struct proc *procp;
{
	pcopy_locked = 0;
}
