xref: /onnv-gate/usr/src/uts/i86pc/vm/hat_pte.h (revision 5349:01422ec04372)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #ifndef	_VM_HAT_PTE_H
270Sstevel@tonic-gate #define	_VM_HAT_PTE_H
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #ifdef	__cplusplus
320Sstevel@tonic-gate extern "C" {
330Sstevel@tonic-gate #endif
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/types.h>
363446Smrj #include <sys/mach_mmu.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * macros to get/set/clear the PTE fields
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate #define	PTE_SET(p, f)	((p) |= (f))
420Sstevel@tonic-gate #define	PTE_CLR(p, f)	((p) &= ~(x86pte_t)(f))
430Sstevel@tonic-gate #define	PTE_GET(p, f)	((p) & (f))
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Handy macro to check if a pagetable entry or pointer is valid
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate #define	PTE_ISVALID(p)		PTE_GET(p, PT_VALID)
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate  * Does a PTE map a large page.
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate #define	PTE_IS_LGPG(p, l)	((l) > 0 && PTE_GET((p), PT_PAGESIZE))
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * does this PTE represent a page (not a pointer to another page table)?
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate #define	PTE_ISPAGE(p, l)	\
590Sstevel@tonic-gate 	(PTE_ISVALID(p) && ((l) == 0 || PTE_GET(p, PT_PAGESIZE)))
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*
625084Sjohnlev  * Handy macro to check if 2 PTE's are the same - ignores REF/MOD bits.
635316Sjohnlev  * On the 64 bit hypervisor we also have to ignore the high order
645316Sjohnlev  * software bits and the global/user bit which are set/cleared
655316Sjohnlev  * capriciously (by the hypervisor!)
660Sstevel@tonic-gate  */
675084Sjohnlev #if defined(__amd64) && defined(__xpv)
685316Sjohnlev #define	PT_IGNORE	((0x7fful << 52) | PT_GLOBAL | PT_USER)
695084Sjohnlev #else
705084Sjohnlev #define	PT_IGNORE	(0)
715084Sjohnlev #endif
725084Sjohnlev #define	PTE_EQUIV(a, b)	 (((a) | (PT_IGNORE | PT_REF | PT_MOD)) == \
735084Sjohnlev 	((b) | (PT_IGNORE | PT_REF | PT_MOD)))
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Shorthand for converting a PTE to it's pfn.
770Sstevel@tonic-gate  */
783446Smrj #define	PTE2MFN(p, l)	\
790Sstevel@tonic-gate 	mmu_btop(PTE_GET((p), PTE_IS_LGPG((p), (l)) ? PT_PADDR_LGPG : PT_PADDR))
805084Sjohnlev #ifdef __xpv
815084Sjohnlev #define	PTE2PFN(p, l) pte2pfn(p, l)
825084Sjohnlev #else
833446Smrj #define	PTE2PFN(p, l) PTE2MFN(p, l)
845084Sjohnlev #endif
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #define	PT_NX		(0x8000000000000000ull)
873446Smrj #define	PT_PADDR	(0x000ffffffffff000ull)
883446Smrj #define	PT_PADDR_LGPG	(0x000fffffffffe000ull)	/* phys addr for large pages */
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * Macros to create a PTP or PTE from the pfn and level
920Sstevel@tonic-gate  */
935084Sjohnlev #ifdef __xpv
945084Sjohnlev 
955084Sjohnlev /*
965084Sjohnlev  * we use the highest order bit in physical address pfns to mark foreign mfns
975084Sjohnlev  */
985084Sjohnlev #ifdef _LP64
995084Sjohnlev #define	PFN_IS_FOREIGN_MFN (1ul << 51)
1005084Sjohnlev #else
1015084Sjohnlev #define	PFN_IS_FOREIGN_MFN (1ul << 31)
1025084Sjohnlev #endif
1035084Sjohnlev 
1045084Sjohnlev #define	MAKEPTP(pfn, l)	\
1055084Sjohnlev 	(pa_to_ma(pfn_to_pa(pfn)) | mmu.ptp_bits[(l) + 1])
1065084Sjohnlev #define	MAKEPTE(pfn, l) \
1075084Sjohnlev 	((pfn & PFN_IS_FOREIGN_MFN) ? \
1085084Sjohnlev 	((pfn_to_pa(pfn & ~PFN_IS_FOREIGN_MFN) | mmu.pte_bits[l]) | \
1095084Sjohnlev 	PT_FOREIGN | PT_REF | PT_MOD) : \
1105084Sjohnlev 	(pa_to_ma(pfn_to_pa(pfn)) | mmu.pte_bits[l]))
1115084Sjohnlev #else
1120Sstevel@tonic-gate #define	MAKEPTP(pfn, l)	\
1133446Smrj 	(pfn_to_pa(pfn) | mmu.ptp_bits[(l) + 1])
1140Sstevel@tonic-gate #define	MAKEPTE(pfn, l)	\
1153446Smrj 	(pfn_to_pa(pfn) | mmu.pte_bits[l])
1165084Sjohnlev #endif
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate  * The idea of "level" refers to the level where the page table is used in the
1200Sstevel@tonic-gate  * the hardware address translation steps. The level values correspond to the
1210Sstevel@tonic-gate  * following names of tables used in AMD/Intel architecture documents:
1220Sstevel@tonic-gate  *
1230Sstevel@tonic-gate  *	AMD/INTEL name		Level #
1240Sstevel@tonic-gate  *	----------------------	-------
1250Sstevel@tonic-gate  *	Page Map Level 4	   3
1260Sstevel@tonic-gate  *	Page Directory Pointer	   2
1270Sstevel@tonic-gate  *	Page Directory		   1
1280Sstevel@tonic-gate  *	Page Table		   0
1290Sstevel@tonic-gate  *
1300Sstevel@tonic-gate  * The numbering scheme is such that the values of 0 and 1 can correspond to
1310Sstevel@tonic-gate  * the pagesize codes used for MPSS support. For now the Maximum level at
1320Sstevel@tonic-gate  * which you can have a large page is a constant, that may change in
1330Sstevel@tonic-gate  * future processors.
1340Sstevel@tonic-gate  *
1350Sstevel@tonic-gate  * The type of "level_t" is signed so that it can be used like:
1360Sstevel@tonic-gate  *	level_t	l;
1370Sstevel@tonic-gate  *	...
1380Sstevel@tonic-gate  *	while (--l >= 0)
1390Sstevel@tonic-gate  *		...
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate #define	MAX_NUM_LEVEL		4
142*5349Skchow #define	MAX_PAGE_LEVEL		2
1433446Smrj typedef	int8_t level_t;
1440Sstevel@tonic-gate #define	LEVEL_SHIFT(l)	(mmu.level_shift[l])
1450Sstevel@tonic-gate #define	LEVEL_SIZE(l)	(mmu.level_size[l])
1460Sstevel@tonic-gate #define	LEVEL_OFFSET(l)	(mmu.level_offset[l])
1470Sstevel@tonic-gate #define	LEVEL_MASK(l)	(mmu.level_mask[l])
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * Macros to:
1510Sstevel@tonic-gate  * Check for a PFN above 4Gig and 64Gig for 32 bit PAE support
1520Sstevel@tonic-gate  */
1530Sstevel@tonic-gate #define	PFN_4G		(4ull * (1024 * 1024 * 1024 / MMU_PAGESIZE))
1540Sstevel@tonic-gate #define	PFN_64G		(64ull * (1024 * 1024 * 1024 / MMU_PAGESIZE))
1550Sstevel@tonic-gate #define	PFN_ABOVE4G(pfn) ((pfn) >= PFN_4G)
1560Sstevel@tonic-gate #define	PFN_ABOVE64G(pfn) ((pfn) >= PFN_64G)
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * The CR3 register holds the physical address of the top level page table.
1600Sstevel@tonic-gate  */
1613446Smrj #define	MAKECR3(pfn)	mmu_ptob(pfn)
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate /*
1640Sstevel@tonic-gate  * HAT/MMU parameters that depend on kernel mode and/or processor type
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate struct htable;
1670Sstevel@tonic-gate struct hat_mmu_info {
1680Sstevel@tonic-gate 	x86pte_t pt_nx;		/* either 0 or PT_NX */
1690Sstevel@tonic-gate 	x86pte_t pt_global;	/* either 0 or PT_GLOBAL */
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	pfn_t highest_pfn;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	uint_t num_level;	/* number of page table levels in use */
1740Sstevel@tonic-gate 	uint_t max_level;	/* just num_level - 1 */
1750Sstevel@tonic-gate 	uint_t max_page_level;	/* maximum level at which we can map a page */
176*5349Skchow 	uint_t umax_page_level; /* max user page map level */
1770Sstevel@tonic-gate 	uint_t ptes_per_table;	/* # of entries in lower level page tables */
1780Sstevel@tonic-gate 	uint_t top_level_count;	/* # of entries in top most level page table */
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	uint_t	hash_cnt;	/* cnt of entries in htable_hash_cache */
1810Sstevel@tonic-gate 	uint_t	vlp_hash_cnt;	/* cnt of entries in vlp htable_hash_cache */
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	uint_t pae_hat;		/* either 0 or 1 */
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	uintptr_t hole_start;	/* start of VA hole (or -1 if none) */
1860Sstevel@tonic-gate 	uintptr_t hole_end;	/* end of VA hole (or 0 if none) */
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	struct htable **kmap_htables; /* htables for segmap + 32 bit heap */
1890Sstevel@tonic-gate 	x86pte_t *kmap_ptes;	/* mapping of pagetables that map kmap */
1900Sstevel@tonic-gate 	uintptr_t kmap_addr;	/* start addr of kmap */
1910Sstevel@tonic-gate 	uintptr_t kmap_eaddr;	/* end addr of kmap */
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	uint_t pte_size;	/* either 4 or 8 */
1940Sstevel@tonic-gate 	uint_t pte_size_shift;	/* either 2 or 3 */
1950Sstevel@tonic-gate 	x86pte_t ptp_bits[MAX_NUM_LEVEL];	/* bits set for interior PTP */
1960Sstevel@tonic-gate 	x86pte_t pte_bits[MAX_NUM_LEVEL];	/* bits set for leaf PTE */
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	/*
1993446Smrj 	 * A range of VA used to window pages in the i86pc/vm code.
2003446Smrj 	 * See PWIN_XXX macros.
2013446Smrj 	 */
2023446Smrj 	caddr_t	pwin_base;
2033446Smrj 	caddr_t	pwin_pte_va;
2043446Smrj 	paddr_t	pwin_pte_pa;
2053446Smrj 
2063446Smrj 	/*
2070Sstevel@tonic-gate 	 * The following tables are equivalent to PAGEXXXXX at different levels
2080Sstevel@tonic-gate 	 * in the page table hierarchy.
2090Sstevel@tonic-gate 	 */
2100Sstevel@tonic-gate 	uint_t level_shift[MAX_NUM_LEVEL];	/* PAGESHIFT for given level */
2110Sstevel@tonic-gate 	uintptr_t level_size[MAX_NUM_LEVEL];	/* PAGESIZE for given level */
2120Sstevel@tonic-gate 	uintptr_t level_offset[MAX_NUM_LEVEL];	/* PAGEOFFSET for given level */
2130Sstevel@tonic-gate 	uintptr_t level_mask[MAX_NUM_LEVEL];	/* PAGEMASK for given level */
2140Sstevel@tonic-gate };
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate #if defined(_KERNEL)
2183446Smrj 
2193446Smrj /*
2203446Smrj  * Macros to access the HAT's private page windows. They're used for
2213446Smrj  * accessing pagetables, ppcopy() and page_zero().
2223446Smrj  * The 1st two macros are used to get an index for the particular use.
2233446Smrj  * The next three give you:
2243446Smrj  * - the virtual address of the window
2253446Smrj  * - the virtual address of the pte that maps the window
2263446Smrj  * - the physical address of the pte that map the window
2273446Smrj  */
2283446Smrj #define	PWIN_TABLE(cpuid)	((cpuid) * 2)
2293446Smrj #define	PWIN_SRC(cpuid)		((cpuid) * 2 + 1)	/* for x86pte_copy() */
2303446Smrj #define	PWIN_VA(x)		(mmu.pwin_base + ((x) << MMU_PAGESHIFT))
2313446Smrj #define	PWIN_PTE_VA(x)		(mmu.pwin_pte_va + ((x) << mmu.pte_size_shift))
2323446Smrj #define	PWIN_PTE_PA(x)		(mmu.pwin_pte_pa + ((x) << mmu.pte_size_shift))
2333446Smrj 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * The concept of a VA hole exists in AMD64. This might need to be made
2360Sstevel@tonic-gate  * model specific eventually.
23747Sjosephb  *
23847Sjosephb  * In the 64 bit kernel PTE loads are atomic, but need cas64 on 32 bit kernel.
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate #if defined(__amd64)
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate #ifdef lint
2430Sstevel@tonic-gate #define	IN_VA_HOLE(va)	(__lintzero)
2440Sstevel@tonic-gate #else
2450Sstevel@tonic-gate #define	IN_VA_HOLE(va)	(mmu.hole_start <= (va) && (va) < mmu.hole_end)
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate 
2483446Smrj #define	FMT_PTE "0x%lx"
2493446Smrj #define	GET_PTE(ptr)		(*(x86pte_t *)(ptr))
2503446Smrj #define	SET_PTE(ptr, pte)	(*(x86pte_t *)(ptr) = pte)
2513446Smrj #define	CAS_PTE(ptr, x, y)	cas64(ptr, x, y)
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate #elif defined(__i386)
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate #define	IN_VA_HOLE(va)	(__lintzero)
2563446Smrj 
2573446Smrj #define	FMT_PTE "0x%llx"
2580Sstevel@tonic-gate 
2593446Smrj /* on 32 bit kernels, 64 bit loads aren't atomic, use get_pte64() */
2603446Smrj extern x86pte_t get_pte64(x86pte_t *ptr);
2613446Smrj #define	GET_PTE(ptr)	(mmu.pae_hat ? get_pte64(ptr) : *(x86pte32_t *)(ptr))
2623446Smrj #define	SET_PTE(ptr, pte)						\
2633446Smrj 	((mmu.pae_hat ? ((x86pte32_t *)(ptr))[1] = (pte >> 32) : 0),	\
2643446Smrj 	*(x86pte32_t *)(ptr) = pte)
2653446Smrj #define	CAS_PTE(ptr, x, y)			\
2663446Smrj 	(mmu.pae_hat ? cas64(ptr, x, y) :	\
2673446Smrj 	cas32((uint32_t *)(ptr), (uint32_t)(x), (uint32_t)(y)))
2680Sstevel@tonic-gate 
26947Sjosephb #endif	/* __i386 */
2700Sstevel@tonic-gate 
2713446Smrj /*
2723446Smrj  * Return a pointer to the pte entry at the given index within a page table.
2733446Smrj  */
2743446Smrj #define	PT_INDEX_PTR(p, x) \
2753446Smrj 	((x86pte_t *)((uintptr_t)(p) + ((x) << mmu.pte_size_shift)))
2763446Smrj 
2773446Smrj /*
2783446Smrj  * Return the physical address of the pte entry at the given index within a
2793446Smrj  * page table.
2803446Smrj  */
2813446Smrj #define	PT_INDEX_PHYSADDR(p, x) \
2823446Smrj 	((paddr_t)(p) + ((x) << mmu.pte_size_shift))
2833446Smrj 
2843446Smrj /*
2853446Smrj  * From pfn to bytes, careful not to lose bits on PAE.
2863446Smrj  */
2873446Smrj #define	pfn_to_pa(pfn) (mmu_ptob((paddr_t)(pfn)))
2880Sstevel@tonic-gate 
2895084Sjohnlev #ifdef __xpv
2905084Sjohnlev extern pfn_t pte2pfn(x86pte_t, level_t);
2915084Sjohnlev #endif
2925084Sjohnlev 
2930Sstevel@tonic-gate extern struct hat_mmu_info mmu;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate #endif	/* _KERNEL */
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate #ifdef	__cplusplus
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate #endif
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate #endif	/* _VM_HAT_PTE_H */
303