/*	Copyright (c) 1984, 1986, 1987, 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
/*	  All Rights Reserved	*/

/*	This Module contains Proprietary Information of Microsoft  */
/*	Corporation and should be treated as Confidential.	   */

#ident	"@(#)head.sys:immu.h	1.6.1.3"

/*
 * NOTE: Page Table entries are caled pde's (page descriptors)
 *	 and Page Directory entries are called pdte's. This is
 *	 not the best naming scheme but it minimizes the changes
 *	 required to the base source.
 */

/*
 * Page Table (descriptor) Entry Definitions
 */

typedef union pde {    /*  page descriptor (table) entry  */
/*    	                                                */
/*  +---------------------+---+--+--+--+-+-+--+-+-+-+  */
/*  |        pfn          |lck|nr|cw|  |m|r|  |u|r|p|  */
/*  +---------------------+---+--+--+--+-+-+--+-+-+-+  */
/*             20            1  1  1  2 1 1  2 1 1 1   */
/*                                                      */
	struct {
		uint pg_pres	:  1,	/* Page is present in memory */
		     pg_rw	:  1,	/* read/write */
		     pg_us	:  1,	/* user/supervisor */
		     		:  2,	/* Reserved by hardware.	*/
		     pg_ref	:  1,	/* Page has been referenced */
		     pg_mod	:  1,	/* Page has been modified */
				:  2,	/* Reserved by hardware.	*/
		     pg_cw	:  1,	/* Copy on write (fault	*/
		     pg_ndref	:  1,	/* Needs reference (software).	*/
		     pg_lock	:  1,	/* Lock in core (software) */
		     pg_pfn	: 20;	/* Physical page frame number */
	} pgm;

	struct {
		uint	pg_pde;		/* Full page table entry */
	} pgi;
} pde_t;

#define pg_v	pg_pres		/* present bit = valid bit */

/*
 *	Page Table
 */

#define NPGPT		1024		/* Nbr of pages per page table */
typedef union ptbl {
	int page[NPGPT];
} ptbl_t;

/* Page table entry dependent constants */

#define	NBPP		4096		/* Number of bytes per page */
#define	NBPPT		4096		/* Number of bytes per page table */
#define	BPTSHFT		12 		/* LOG2(NBPPT) if exact */
#define NDPP            8               /* Number of disk blocks per page */
#define DPPSHFT         3               /* Shift for disk blocks per page. */
/* Following added because svid says ulimit works in 512 byte units, so we must
  have something independent of the blocksize of the file system implementation
 */
#define NUPP		8		/* Number ulimit blocks per page    */
#define UPPSHFT		3		/* Shift for ulimit blocks per page */

#define PNUMSHFT	12		/* Shift for page number from addr. */
#define POFFMASK        0xFFF		/* Mask for offset into page. */
#define	PTOFFMASK	0x3FF		/* Mask for offset into page table/dir*/
#define	PNDXMASK	PTOFFMASK	/* Mask for offset into kptbl.*/
#define PGFNMASK	0xFFFFF		/* Mask page frame nbr after shift. */
#define PTNUMSHFT	22		/* Shift for page table num from addr */

#define	NPTPP		1		/* Nbr of page tables per page.	*/
#define	NPTPPSHFT	0		/* Shift for NPTPP. */

/* Page descriptor (table) entry field masks */

#define PG_ADDR		0xFFFFF000	/* physical page address */
#define PG_LOCK		0x00000800	/* page lock bit (software) */
#define PG_NDREF	0x00000400	/* need reference bit (software) */
#define PG_COPYW	0x00000200	/* copy on write bit */
#define PG_M		0x00000040	/* modify bit */
#define PG_REF		0x00000020	/* reference bit */
#define	PG_US		0x00000004	/* 0=supervisor, 1=user */
#define	PG_RW		0x00000002	/* 0=read-only, 1=read/write */
#define PG_P		0x00000001	/* page present bit */
#define PTE_RW		(PG_RW|PG_US)

#define PTSIZE		4096		/* page table size in bytes */
#define PTSZSHFT	12		/* page table size shift count */


/* byte addr to virtual page */

#define pnum(X)   (((uint)(X) >> PNUMSHFT) & PTOFFMASK) 

/* page frame number */

#define pfnum(X) (((uint)(X) >> PNUMSHFT) & PGFNMASK)

/* page offset */

#define poff(X)   ((uint)(X) & POFFMASK)

/* page table num (page dir entry) */

#define ptnum(X)	((uint)(X) >> PTNUMSHFT)

#define pgndx(X)	(((X) >> PNUMSHFT) & PNDXMASK)

/* Round up page table address */

#define ptround(p)	((int *) (((int)p + PTSIZE-1) & ~(PTSIZE-1)))

/* Round down page table address */

#define ptalign(p)	((int *) ((int)p & ~(PTSIZE-1)))

/* Following added because svid says ulimit works in 512 byte units, so we must
  have something independent of the blocksize of the file system implementation

	Ulimit blocks (512 bytes each) and pages.
 */

#define utop(UU)	(((UU) + NUPP -1) >> UPPSHFT)

/*	Disk blocks (sectors) and pages.
*/

#define	ptod(PP)	((PP) << DPPSHFT)
#define	dtop(DD)	(((DD) + NDPP - 1) >> DPPSHFT)
#define dtopt(DD)	((DD) >> DPPSHFT)

/*	Disk blocks (sectors) and bytes.
*/

#define	dtob(DD)	((DD) << SCTRSHFT)
#define	btod(BB)	(((BB) + NBPSCTR - 1) >> SCTRSHFT)
#define	btodt(BB)	((BB) >> SCTRSHFT)

/*	Page tables to pages.
*/

#define	pttopgs(X)	((X + NPTPP - 1) >> NPTPPSHFT)
#define	pttob(X)	((X) << BPTSHFT)
#define	btopt(X)	(((X) + NBPPT - 1) >> BPTSHFT)

union ptbl *getptbl();		/* page table allocator */

extern int		nptalloced;
extern int		nptfree;

/* Form page descriptor (table) entry from modes and page frame
** number
*/

#define	mkpde(mode,pfn)	(mode | ((pfn) << PNUMSHFT))

/*	The following macros are used to check the value
 *	of the bits in a page descriptor (table) entry 
 */

#define pg_isvalid(pde) 	((pde)->pgm.pg_pres)
#define pg_islocked(pde)	((pde)->pgm.pg_lock)
#define pg_iswriteable(pde)     ((pde)->pgm.pg_rw)

/*	The following macros are used to set the value
 *	of the bits in a page table entry 
 *
 *	Atomic instruction is available to clear the present bit,
 *	other bits are set or cleared in a word operation.
 */

#define pg_setvalid(P)	((P)->pgi.pg_pde |= PG_P) /* Set valid bit.	*/
#define pg_clrvalid(P)	((P)->pgi.pg_pde &= ~PG_P) /* Clear valid bit.	*/

#define pg_setndref(P)	((P)->pgi.pg_pde |= PG_NDREF)
						/* Set need ref bit.	*/
#define pg_clrndref(P)	((P)->pgi.pg_pde &= ~PG_NDREF)
						/* Clr need ref bit.	*/

#define pg_setlock(P)	((P)->pgi.pg_pde |= PG_LOCK)	
						/* Set lock bit.	*/
#define pg_clrlock(P)	((P)->pgi.pg_pde &= ~PG_LOCK) /* Clear lock bit.	*/

#define pg_setmod(P)	((P)->pgi.pg_pde |= PG_M)	
						/* Set modify bit.	*/
#define pg_clrmod(P)	((P)->pgi.pg_pde &= ~PG_M)	
						/* Clear modify bit.	*/

#define pg_setcw(P)	((P)->pgi.pg_pde |= PG_COPYW), \
			((P)->pgi.pg_pde &= ~PG_RW)
						/* Set copy on write
						 * and clear r/w
						 */

#define pg_clrcw(P)	((P)->pgi.pg_pde &= ~PG_COPYW) /* Clr copy on write.*/

#define pg_setref(P)	((P)->pgi.pg_pde |= PG_REF) 	/* Set ref bit.	*/
#define pg_clrref(P)	((P)->pgi.pg_pde &= ~PG_REF) /* Clear ref bit.	*/

#define pg_setprot(P,b)	((P)->pgi.pg_pde |= b)	/* Set r/w access */

#define	SOFFMASK	0x3FFFFF	/* Mask for page table alignment */
#define	SGENDMASK	0x3FFFFC	/* Mask for page table end alignment */

/*  access modes  */

#define KNONE  (unsigned char)  0x00
#define KEO    (unsigned char)  0x40	/* KRO on WE32000	*/
#define KRE    (unsigned char)  0x80
#define KRWE   (unsigned char)  0xC0	/* KRW on WE32000	*/

#define UNONE  (unsigned char)  0x00
#define UEO    (unsigned char)  0x01	/* URO on WE32000	*/
#define URE    (unsigned char)  0x02
#define URWE   (unsigned char)  0x03	/* URW on WE32000	*/

#define UACCESS (unsigned char) 0x03
#define KACCESS (unsigned char) 0xC0

#define SEG_RO	(KRWE|URE)
#define SEG_RW	(KRWE|URWE)

/*	The following variables describe the memory managed by
**	the kernel.  This includes all memory above the kernel
**	itself.
*/

extern paddr_t	kpbase;		/* The address of the start of	*/
				/* the first physical page of	*/
				/* memory above the kernel.	*/
				/* Physical memory from here to	*/
				/* the end of physical memory	*/
				/* is represented in the pfdat.	*/
extern int	syssegs[];	/* Start of the system segment	*/
				/* from which kernel space is	*/
				/* allocated.  The actual value	*/
				/* is defined in the vuifile.	*/
extern int	win_ublk[];	/* A window into which a	*/
				/* u-block can be mapped.	*/
extern pde_t	*kptbl;		/* Kernel page table.  Used to	*/
				/* map sysseg.			*/
extern pde_t	*usertable;	/* Common page table.  Used to	*/
				/* map the current ublock.	*/
extern int	maxmem;		/* Maximum available free	*/
				/* memory.			*/
extern int	freemem;	/* Current free memory.		*/
extern int	availrmem;	/* Available resident (not	*/
				/* swapable) memory in pages.	*/
extern int	availsmem;	/* Available swapable memory in	*/
				/* pages.			*/

/*	Conversion macros
*/

/*	Get page number from system virtual address.  */

#define svtop(vaddr)    ((paddr_t)((vaddr) - KVBASE) >> PNUMSHFT)

/*	Get system virtual address from page number.  */

#define ptosv(paddr)    (((paddr) << PNUMSHFT) + KVBASE)


/*	These macros are used to map between kernel virtual
**      and physical address.
*/

#define kvtophys(vaddr) ((paddr_t)svirtophys(vaddr))
#define phystokv(paddr) ((paddr) + KVBASE)

/*	The xphystokv() macro works for all physical addresses
**	which correspond to main (RAM) memory.  This differs from
**	phystokv() in that it can handle the Olivetti's extra 384K.
**	Normally, this isn't an issue, since this 384K is used for
**	kernel text.
*/

#define xphystokv(paddr) (((paddr) & 0x80000000) ? \
		(paddr) + (KVXBASE - 0x80000000) : (paddr) + KVBASE)

/*	Between kernel virtual address and physical page frame number.
*/

#define kvtopfn(vaddr) (kvtophys(vaddr) >> PNUMSHFT)
#define pfntokv(pfn)   (phystokv ((pfn) << PNUMSHFT))

/*	Between kernel virtual addresses and the kernel page
**	table.
*/

#define	kvtokptbl(X)	(&kptbl[pgndx((uint)(X) - (uint)syssegs)])

/*	The following routines are involved with the pfdat
**	table described in pfdat.h
*/

#define	kvtopfdat(kv)	(&pfdat[kvtopfn(kv) - btoc(kpbase)])
#define	pfntopfdat(pfn)	(&pfdat[pfn - btoc(kpbase)])
#define	pfdattopfn(pfd)	(pfd - pfdat + btoc(kpbase))

#ifndef	MSDEBUGGER
/*
 * pde_t *
 * vatopdte(v)
 * returns the page directory entry location of v.
 */

#define	vatopdte(v)	((pde_t *)phystokv(_cr3()) + ptnum(v))
#else
#define	vatopdte(v)	((pde_t *) db_vtopdte(v))
#endif

/*
 * pde_t *
 * vatopde(v, pdte)
 * returns the page table entry location of v.
 */

#define	vatopde(v, pdte) ((pde_t *)phystokv(ctob(pdte->pgm.pg_pfn)) + pnum(v))

/*
 * pde_t *
 * svtopde(v)
 * returns the pt entry location of v.
 *
 * This macro works only with paged virtual address.
 *
 */

#define svtopde(v) ((pde_t *)phystokv(ctob((uint)(vatopdte(v)->pgm.pg_pfn))) + pnum(v))

/*
 * svtopfn(v)
 */

#define svtopfn(v) (pfnum(svirtophys(v)))

/*	Page frame number to kernel pde.
*/

#define	pfntokptbl(P)	(kvtokptbl(pfntokv(P)))

/*	Convert segment:offset 8086 far pointer to address
*/

#define	ftop(x)	((((x) & 0xffff0000) >> 12) + ((x) & 0xffff))

/* flags used in ptmemall() call
*/

#define PHYSCONTIG 02
#define NOSLEEP    01

/*
 *  User address space offsets
 *
 *****************************  NOTE - NOTE  *********************************
 *
 *	 ANY CHANGES IN THE FOLLOWING DEFINES NEED TO BE REFLECTED IN
 *	    EITHER ml/misc.s, OR ml/ttrap.s, OR BOTH.
 */

#define UVBASE          ((unsigned)0x00000000L)     /* main store virtual address    */
#define UVSTACK         ((unsigned)0x7FFFFFFCL)     /* stack bottom virtual address  */
#define UVSHM           ((unsigned)0x80000000L)     /* Shared memory address         */
#define KVBASE          ((unsigned)0xC0000000L)     /* base of kernel memory map     */
#define KVSBASE         ((unsigned)0xD0000000L)     /* base for kernel text, data + bss */
#define KVXBASE         ((unsigned)0xD8000000L)     /* base for extended memory      */
#define UVUBLK          ((unsigned)0xE0000000L)     /* ublock virtual address        */

#define UVTEXT          UVBASE          /* beginning addrss of user text    */
#define MINUVADR        UVTEXT          /* minimum user virtual address.    */
#define MAXUVADR        KVBASE          /* maximum user virtual address.    */
#define MINKVADR        KVBASE          /* minimum kernel virtual address.  */
#define MAXKVADR        UVUBLK          /* maximum kernel virtual address.  */

#define KADDR(v)        ((v) >= MINKVADR && (v) < MAXKVADR)

#define	SEL_RPL		0x03
