xref: /illumos-gate/usr/src/uts/i86pc/vm/hat_pte.h (revision 4e5b757f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #ifndef	_VM_HAT_PTE_H
27 #define	_VM_HAT_PTE_H
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #ifdef	__cplusplus
32 extern "C" {
33 #endif
34 
35 #include <sys/types.h>
36 #include <sys/mach_mmu.h>
37 
38 /*
39  * macros to get/set/clear the PTE fields
40  */
41 #define	PTE_SET(p, f)	((p) |= (f))
42 #define	PTE_CLR(p, f)	((p) &= ~(x86pte_t)(f))
43 #define	PTE_GET(p, f)	((p) & (f))
44 
45 /*
46  * Handy macro to check if a pagetable entry or pointer is valid
47  */
48 #define	PTE_ISVALID(p)		PTE_GET(p, PT_VALID)
49 
50 /*
51  * Does a PTE map a large page.
52  */
53 #define	PTE_IS_LGPG(p, l)	((l) > 0 && PTE_GET((p), PT_PAGESIZE))
54 
55 /*
56  * does this PTE represent a page (not a pointer to another page table)?
57  */
58 #define	PTE_ISPAGE(p, l)	\
59 	(PTE_ISVALID(p) && ((l) == 0 || PTE_GET(p, PT_PAGESIZE)))
60 
61 /*
62  * Handy macro to check if 2 PTE's are the same - ignores REF/MOD bits
63  */
64 #define	PTE_EQUIV(a, b)	 (((a) | PT_REF | PT_MOD) == ((b) | PT_REF | PT_MOD))
65 
66 /*
67  * Shorthand for converting a PTE to it's pfn.
68  */
69 #define	PTE2MFN(p, l)	\
70 	mmu_btop(PTE_GET((p), PTE_IS_LGPG((p), (l)) ? PT_PADDR_LGPG : PT_PADDR))
71 #define	PTE2PFN(p, l) PTE2MFN(p, l)
72 
73 #define	PT_NX		(0x8000000000000000ull)
74 #define	PT_PADDR	(0x000ffffffffff000ull)
75 #define	PT_PADDR_LGPG	(0x000fffffffffe000ull)	/* phys addr for large pages */
76 
77 /*
78  * Macros to create a PTP or PTE from the pfn and level
79  */
80 #define	MAKEPTP(pfn, l)	\
81 	(pfn_to_pa(pfn) | mmu.ptp_bits[(l) + 1])
82 #define	MAKEPTE(pfn, l)	\
83 	(pfn_to_pa(pfn) | mmu.pte_bits[l])
84 
85 /*
86  * The idea of "level" refers to the level where the page table is used in the
87  * the hardware address translation steps. The level values correspond to the
88  * following names of tables used in AMD/Intel architecture documents:
89  *
90  *	AMD/INTEL name		Level #
91  *	----------------------	-------
92  *	Page Map Level 4	   3
93  *	Page Directory Pointer	   2
94  *	Page Directory		   1
95  *	Page Table		   0
96  *
97  * The numbering scheme is such that the values of 0 and 1 can correspond to
98  * the pagesize codes used for MPSS support. For now the Maximum level at
99  * which you can have a large page is a constant, that may change in
100  * future processors.
101  *
102  * The type of "level_t" is signed so that it can be used like:
103  *	level_t	l;
104  *	...
105  *	while (--l >= 0)
106  *		...
107  */
108 #define	MAX_NUM_LEVEL		4
109 #define	MAX_PAGE_LEVEL		1			/* for now.. sigh */
110 typedef	int8_t level_t;
111 #define	LEVEL_SHIFT(l)	(mmu.level_shift[l])
112 #define	LEVEL_SIZE(l)	(mmu.level_size[l])
113 #define	LEVEL_OFFSET(l)	(mmu.level_offset[l])
114 #define	LEVEL_MASK(l)	(mmu.level_mask[l])
115 
116 /*
117  * Macros to:
118  * Check for a PFN above 4Gig and 64Gig for 32 bit PAE support
119  */
120 #define	PFN_4G		(4ull * (1024 * 1024 * 1024 / MMU_PAGESIZE))
121 #define	PFN_64G		(64ull * (1024 * 1024 * 1024 / MMU_PAGESIZE))
122 #define	PFN_ABOVE4G(pfn) ((pfn) >= PFN_4G)
123 #define	PFN_ABOVE64G(pfn) ((pfn) >= PFN_64G)
124 
125 /*
126  * The CR3 register holds the physical address of the top level page table.
127  */
128 #define	MAKECR3(pfn)	mmu_ptob(pfn)
129 
130 /*
131  * HAT/MMU parameters that depend on kernel mode and/or processor type
132  */
133 struct htable;
134 struct hat_mmu_info {
135 	x86pte_t pt_nx;		/* either 0 or PT_NX */
136 	x86pte_t pt_global;	/* either 0 or PT_GLOBAL */
137 
138 	pfn_t highest_pfn;
139 
140 	uint_t num_level;	/* number of page table levels in use */
141 	uint_t max_level;	/* just num_level - 1 */
142 	uint_t max_page_level;	/* maximum level at which we can map a page */
143 	uint_t ptes_per_table;	/* # of entries in lower level page tables */
144 	uint_t top_level_count;	/* # of entries in top most level page table */
145 
146 	uint_t	hash_cnt;	/* cnt of entries in htable_hash_cache */
147 	uint_t	vlp_hash_cnt;	/* cnt of entries in vlp htable_hash_cache */
148 
149 	uint_t pae_hat;		/* either 0 or 1 */
150 
151 	uintptr_t hole_start;	/* start of VA hole (or -1 if none) */
152 	uintptr_t hole_end;	/* end of VA hole (or 0 if none) */
153 
154 	struct htable **kmap_htables; /* htables for segmap + 32 bit heap */
155 	x86pte_t *kmap_ptes;	/* mapping of pagetables that map kmap */
156 	uintptr_t kmap_addr;	/* start addr of kmap */
157 	uintptr_t kmap_eaddr;	/* end addr of kmap */
158 
159 	uint_t pte_size;	/* either 4 or 8 */
160 	uint_t pte_size_shift;	/* either 2 or 3 */
161 	x86pte_t ptp_bits[MAX_NUM_LEVEL];	/* bits set for interior PTP */
162 	x86pte_t pte_bits[MAX_NUM_LEVEL];	/* bits set for leaf PTE */
163 
164 	/*
165 	 * A range of VA used to window pages in the i86pc/vm code.
166 	 * See PWIN_XXX macros.
167 	 */
168 	caddr_t	pwin_base;
169 	caddr_t	pwin_pte_va;
170 	paddr_t	pwin_pte_pa;
171 
172 	/*
173 	 * The following tables are equivalent to PAGEXXXXX at different levels
174 	 * in the page table hierarchy.
175 	 */
176 	uint_t level_shift[MAX_NUM_LEVEL];	/* PAGESHIFT for given level */
177 	uintptr_t level_size[MAX_NUM_LEVEL];	/* PAGESIZE for given level */
178 	uintptr_t level_offset[MAX_NUM_LEVEL];	/* PAGEOFFSET for given level */
179 	uintptr_t level_mask[MAX_NUM_LEVEL];	/* PAGEMASK for given level */
180 };
181 
182 
183 #if defined(_KERNEL)
184 
185 /*
186  * Macros to access the HAT's private page windows. They're used for
187  * accessing pagetables, ppcopy() and page_zero().
188  * The 1st two macros are used to get an index for the particular use.
189  * The next three give you:
190  * - the virtual address of the window
191  * - the virtual address of the pte that maps the window
192  * - the physical address of the pte that map the window
193  */
194 #define	PWIN_TABLE(cpuid)	((cpuid) * 2)
195 #define	PWIN_SRC(cpuid)		((cpuid) * 2 + 1)	/* for x86pte_copy() */
196 #define	PWIN_VA(x)		(mmu.pwin_base + ((x) << MMU_PAGESHIFT))
197 #define	PWIN_PTE_VA(x)		(mmu.pwin_pte_va + ((x) << mmu.pte_size_shift))
198 #define	PWIN_PTE_PA(x)		(mmu.pwin_pte_pa + ((x) << mmu.pte_size_shift))
199 
200 /*
201  * The concept of a VA hole exists in AMD64. This might need to be made
202  * model specific eventually.
203  *
204  * In the 64 bit kernel PTE loads are atomic, but need cas64 on 32 bit kernel.
205  */
206 #if defined(__amd64)
207 
208 #ifdef lint
209 #define	IN_VA_HOLE(va)	(__lintzero)
210 #else
211 #define	IN_VA_HOLE(va)	(mmu.hole_start <= (va) && (va) < mmu.hole_end)
212 #endif
213 
214 #define	FMT_PTE "0x%lx"
215 #define	GET_PTE(ptr)		(*(x86pte_t *)(ptr))
216 #define	SET_PTE(ptr, pte)	(*(x86pte_t *)(ptr) = pte)
217 #define	CAS_PTE(ptr, x, y)	cas64(ptr, x, y)
218 
219 #elif defined(__i386)
220 
221 #define	IN_VA_HOLE(va)	(__lintzero)
222 
223 #define	FMT_PTE "0x%llx"
224 
225 /* on 32 bit kernels, 64 bit loads aren't atomic, use get_pte64() */
226 extern x86pte_t get_pte64(x86pte_t *ptr);
227 #define	GET_PTE(ptr)	(mmu.pae_hat ? get_pte64(ptr) : *(x86pte32_t *)(ptr))
228 #define	SET_PTE(ptr, pte)						\
229 	((mmu.pae_hat ? ((x86pte32_t *)(ptr))[1] = (pte >> 32) : 0),	\
230 	*(x86pte32_t *)(ptr) = pte)
231 #define	CAS_PTE(ptr, x, y)			\
232 	(mmu.pae_hat ? cas64(ptr, x, y) :	\
233 	cas32((uint32_t *)(ptr), (uint32_t)(x), (uint32_t)(y)))
234 
235 #endif	/* __i386 */
236 
237 /*
238  * Return a pointer to the pte entry at the given index within a page table.
239  */
240 #define	PT_INDEX_PTR(p, x) \
241 	((x86pte_t *)((uintptr_t)(p) + ((x) << mmu.pte_size_shift)))
242 
243 /*
244  * Return the physical address of the pte entry at the given index within a
245  * page table.
246  */
247 #define	PT_INDEX_PHYSADDR(p, x) \
248 	((paddr_t)(p) + ((x) << mmu.pte_size_shift))
249 
250 /*
251  * From pfn to bytes, careful not to lose bits on PAE.
252  */
253 #define	pfn_to_pa(pfn) (mmu_ptob((paddr_t)(pfn)))
254 
255 extern struct hat_mmu_info mmu;
256 
257 #endif	/* _KERNEL */
258 
259 
260 #ifdef	__cplusplus
261 }
262 #endif
263 
264 #endif	/* _VM_HAT_PTE_H */
265