xref: /titanic_50/usr/src/uts/i86pc/vm/kboot_mmu.c (revision 613b28719c10e84c1202c1045df44d77767de21d)
1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
5ae115bc7Smrj  * Common Development and Distribution License (the "License").
6ae115bc7Smrj  * You may not use this file except in compliance with the License.
7ae115bc7Smrj  *
8ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj  * See the License for the specific language governing permissions
11ae115bc7Smrj  * and limitations under the License.
12ae115bc7Smrj  *
13ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj  *
19ae115bc7Smrj  * CDDL HEADER END
20ae115bc7Smrj  */
21ae115bc7Smrj 
22ae115bc7Smrj /*
23*613b2871SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24ae115bc7Smrj  * Use is subject to license terms.
25ae115bc7Smrj  */
26ae115bc7Smrj 
27ae115bc7Smrj #include <sys/types.h>
28ae115bc7Smrj #include <sys/systm.h>
29ae115bc7Smrj #include <sys/archsystm.h>
30ae115bc7Smrj #include <sys/debug.h>
31ae115bc7Smrj #include <sys/bootconf.h>
32ae115bc7Smrj #include <sys/bootsvcs.h>
33ae115bc7Smrj #include <sys/bootinfo.h>
34ae115bc7Smrj #include <sys/mman.h>
35ae115bc7Smrj #include <sys/cmn_err.h>
36ae115bc7Smrj #include <sys/param.h>
37ae115bc7Smrj #include <sys/machparam.h>
38ae115bc7Smrj #include <sys/machsystm.h>
39ae115bc7Smrj #include <sys/promif.h>
40ae115bc7Smrj #include <sys/kobj.h>
41843e1988Sjohnlev #ifdef __xpv
42843e1988Sjohnlev #include <sys/hypervisor.h>
43843e1988Sjohnlev #endif
44ae115bc7Smrj #include <vm/kboot_mmu.h>
45ae115bc7Smrj #include <vm/hat_pte.h>
46ae115bc7Smrj #include <vm/hat_i86.h>
47ae115bc7Smrj #include <vm/seg_kmem.h>
48ae115bc7Smrj 
49ae115bc7Smrj #if 0
50ae115bc7Smrj /*
51ae115bc7Smrj  * Joe's debug printing
52ae115bc7Smrj  */
53ae115bc7Smrj #define	DBG(x)    \
54*613b2871SRichard Bean 	bop_printf(NULL, "kboot_mmu.c: %s is %" PRIx64 "\n", #x, (uint64_t)(x));
55ae115bc7Smrj #else
56ae115bc7Smrj #define	DBG(x)	/* naught */
57ae115bc7Smrj #endif
58ae115bc7Smrj 
59ae115bc7Smrj /*
60ae115bc7Smrj  * Page table and memory stuff.
61ae115bc7Smrj  */
62ae115bc7Smrj static caddr_t window;
63ae115bc7Smrj static caddr_t pte_to_window;
64ae115bc7Smrj 
65ae115bc7Smrj /*
66ae115bc7Smrj  * this are needed by mmu_init()
67ae115bc7Smrj  */
68ae115bc7Smrj int kbm_nx_support = 0;		/* NX bit in PTEs is in use */
69ae115bc7Smrj int kbm_pae_support = 0;	/* PAE is 64 bit Page table entries */
70ae115bc7Smrj int kbm_pge_support = 0;	/* PGE is Page table global bit enabled */
71ae115bc7Smrj int kbm_largepage_support = 0;
72ae115bc7Smrj uint_t kbm_nucleus_size = 0;
73ae115bc7Smrj 
74ae115bc7Smrj #define	BOOT_SHIFT(l)	(shift_amt[l])
75ae115bc7Smrj #define	BOOT_SZ(l)	((size_t)1 << BOOT_SHIFT(l))
76ae115bc7Smrj #define	BOOT_OFFSET(l)	(BOOT_SZ(l) - 1)
77ae115bc7Smrj #define	BOOT_MASK(l)	(~BOOT_OFFSET(l))
78ae115bc7Smrj 
79ae115bc7Smrj /*
80ae115bc7Smrj  * Initialize memory management parameters for boot time page table management
81ae115bc7Smrj  */
82ae115bc7Smrj void
kbm_init(struct xboot_info * bi)83ae115bc7Smrj kbm_init(struct xboot_info *bi)
84ae115bc7Smrj {
85ae115bc7Smrj 	/*
86ae115bc7Smrj 	 * configure mmu information
87ae115bc7Smrj 	 */
88ae115bc7Smrj 	kbm_nucleus_size = (uintptr_t)bi->bi_kseg_size;
89ae115bc7Smrj 	kbm_largepage_support = bi->bi_use_largepage;
90ae115bc7Smrj 	kbm_nx_support = bi->bi_use_nx;
91ae115bc7Smrj 	kbm_pae_support = bi->bi_use_pae;
92ae115bc7Smrj 	kbm_pge_support = bi->bi_use_pge;
93ae115bc7Smrj 	window = bi->bi_pt_window;
94ae115bc7Smrj 	DBG(window);
95ae115bc7Smrj 	pte_to_window = bi->bi_pte_to_pt_window;
96ae115bc7Smrj 	DBG(pte_to_window);
97ae115bc7Smrj 	if (kbm_pae_support) {
98ae115bc7Smrj 		shift_amt = shift_amt_pae;
99ae115bc7Smrj 		ptes_per_table = 512;
100ae115bc7Smrj 		pte_size = 8;
101ae115bc7Smrj 		lpagesize = TWO_MEG;
102ae115bc7Smrj #ifdef __amd64
103ae115bc7Smrj 		top_level = 3;
104ae115bc7Smrj #else
105ae115bc7Smrj 		top_level = 2;
106ae115bc7Smrj #endif
107ae115bc7Smrj 	} else {
108ae115bc7Smrj 		shift_amt = shift_amt_nopae;
109ae115bc7Smrj 		ptes_per_table = 1024;
110ae115bc7Smrj 		pte_size = 4;
111ae115bc7Smrj 		lpagesize = FOUR_MEG;
112ae115bc7Smrj 		top_level = 1;
113ae115bc7Smrj 	}
114ae115bc7Smrj 
115843e1988Sjohnlev #ifdef __xpv
116843e1988Sjohnlev 	xen_info = bi->bi_xen_start_info;
117843e1988Sjohnlev 	mfn_list = (mfn_t *)xen_info->mfn_list;
118843e1988Sjohnlev 	DBG(mfn_list);
119843e1988Sjohnlev 	mfn_count = xen_info->nr_pages;
120843e1988Sjohnlev 	DBG(mfn_count);
121843e1988Sjohnlev #endif
122ae115bc7Smrj 	top_page_table = bi->bi_top_page_table;
123ae115bc7Smrj 	DBG(top_page_table);
124ae115bc7Smrj }
125ae115bc7Smrj 
126ae115bc7Smrj /*
127ae115bc7Smrj  * Change the addressible page table window to point at a given page
128ae115bc7Smrj  */
129ae115bc7Smrj /*ARGSUSED*/
130ae115bc7Smrj void *
kbm_remap_window(paddr_t physaddr,int writeable)131ae115bc7Smrj kbm_remap_window(paddr_t physaddr, int writeable)
132ae115bc7Smrj {
133843e1988Sjohnlev 	x86pte_t pt_bits = PT_NOCONSIST | PT_VALID | PT_WRITABLE;
134ae115bc7Smrj 
135ae115bc7Smrj 	DBG(physaddr);
136ae115bc7Smrj 
137843e1988Sjohnlev #ifdef __xpv
138843e1988Sjohnlev 	if (!writeable)
139843e1988Sjohnlev 		pt_bits &= ~PT_WRITABLE;
140843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping((uintptr_t)window,
141843e1988Sjohnlev 	    pa_to_ma(physaddr) | pt_bits, UVMF_INVLPG | UVMF_LOCAL) < 0)
142843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping() failed");
143843e1988Sjohnlev #else
144ae115bc7Smrj 	if (kbm_pae_support)
145ae115bc7Smrj 		*((x86pte_t *)pte_to_window) = physaddr | pt_bits;
146ae115bc7Smrj 	else
147ae115bc7Smrj 		*((x86pte32_t *)pte_to_window) = physaddr | pt_bits;
148ae115bc7Smrj 	mmu_tlbflush_entry(window);
149843e1988Sjohnlev #endif
150ae115bc7Smrj 	DBG(window);
151ae115bc7Smrj 	return (window);
152ae115bc7Smrj }
153ae115bc7Smrj 
154ae115bc7Smrj /*
155ae115bc7Smrj  * Add a mapping for the physical page at the given virtual address.
156ae115bc7Smrj  */
157ae115bc7Smrj void
kbm_map(uintptr_t va,paddr_t pa,uint_t level,uint_t is_kernel)158ae115bc7Smrj kbm_map(uintptr_t va, paddr_t pa, uint_t level, uint_t is_kernel)
159ae115bc7Smrj {
160ae115bc7Smrj 	x86pte_t *ptep;
161ae115bc7Smrj 	paddr_t pte_physaddr;
162ae115bc7Smrj 	x86pte_t pteval;
163ae115bc7Smrj 
164ae115bc7Smrj 	if (khat_running)
165ae115bc7Smrj 		panic("kbm_map() called too late");
166ae115bc7Smrj 
167ae115bc7Smrj 	pteval = pa_to_ma(pa) | PT_NOCONSIST | PT_VALID | PT_WRITABLE;
16802bc52beSkchow 	if (level >= 1)
169ae115bc7Smrj 		pteval |= PT_PAGESIZE;
170ae115bc7Smrj 	if (kbm_pge_support && is_kernel)
171ae115bc7Smrj 		pteval |= PT_GLOBAL;
172ae115bc7Smrj 
173843e1988Sjohnlev #ifdef __xpv
174843e1988Sjohnlev 	/*
175843e1988Sjohnlev 	 * try update_va_mapping first - fails if page table is missing.
176843e1988Sjohnlev 	 */
177843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va, pteval,
178843e1988Sjohnlev 	    UVMF_INVLPG | UVMF_LOCAL) == 0)
179843e1988Sjohnlev 		return;
180843e1988Sjohnlev #endif
181843e1988Sjohnlev 
182ae115bc7Smrj 	/*
183ae115bc7Smrj 	 * Find the pte that will map this address. This creates any
184ae115bc7Smrj 	 * missing intermediate level page tables.
185ae115bc7Smrj 	 */
186ae115bc7Smrj 	ptep = find_pte(va, &pte_physaddr, level, 0);
187ae115bc7Smrj 	if (ptep == NULL)
188ae115bc7Smrj 		bop_panic("kbm_map: find_pte returned NULL");
189ae115bc7Smrj 
190843e1988Sjohnlev #ifdef __xpv
191843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL))
192843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping() failed");
193843e1988Sjohnlev #else
194ae115bc7Smrj 	if (kbm_pae_support)
195ae115bc7Smrj 		*ptep = pteval;
196ae115bc7Smrj 	else
197ae115bc7Smrj 		*((x86pte32_t *)ptep) = pteval;
198ae115bc7Smrj 	mmu_tlbflush_entry((caddr_t)va);
199843e1988Sjohnlev #endif
200ae115bc7Smrj }
201ae115bc7Smrj 
202843e1988Sjohnlev #ifdef __xpv
203843e1988Sjohnlev 
204843e1988Sjohnlev /*
205843e1988Sjohnlev  * Add a mapping for the machine page at the given virtual address.
206843e1988Sjohnlev  */
207843e1988Sjohnlev void
kbm_map_ma(maddr_t ma,uintptr_t va,uint_t level)208843e1988Sjohnlev kbm_map_ma(maddr_t ma, uintptr_t va, uint_t level)
209843e1988Sjohnlev {
210843e1988Sjohnlev 	paddr_t pte_physaddr;
211843e1988Sjohnlev 	x86pte_t pteval;
212843e1988Sjohnlev 
213843e1988Sjohnlev 	pteval = ma | PT_NOCONSIST | PT_VALID | PT_REF | PT_WRITABLE;
214843e1988Sjohnlev 	if (level == 1)
215843e1988Sjohnlev 		pteval |= PT_PAGESIZE;
216843e1988Sjohnlev 
217843e1988Sjohnlev 	/*
218843e1988Sjohnlev 	 * try update_va_mapping first - fails if page table is missing.
219843e1988Sjohnlev 	 */
220843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va,
221843e1988Sjohnlev 	    pteval, UVMF_INVLPG | UVMF_LOCAL) == 0)
222843e1988Sjohnlev 		return;
223843e1988Sjohnlev 
224843e1988Sjohnlev 	/*
225843e1988Sjohnlev 	 * Find the pte that will map this address. This creates any
226843e1988Sjohnlev 	 * missing intermediate level page tables
227843e1988Sjohnlev 	 */
228843e1988Sjohnlev 	(void) find_pte(va, &pte_physaddr, level, 0);
229843e1988Sjohnlev 
230843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va,
231843e1988Sjohnlev 	    pteval, UVMF_INVLPG | UVMF_LOCAL) != 0)
232843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping failed");
233843e1988Sjohnlev }
234843e1988Sjohnlev 
235843e1988Sjohnlev #endif /* __xpv */
236843e1988Sjohnlev 
237843e1988Sjohnlev 
238ae115bc7Smrj /*
239ae115bc7Smrj  * Probe the boot time page tables to find the first mapping
240ae115bc7Smrj  * including va (or higher) and return non-zero if one is found.
241ae115bc7Smrj  * va is updated to the starting address and len to the pagesize.
242ae115bc7Smrj  * pp will be set to point to the 1st page_t of the mapped page(s).
243ae115bc7Smrj  *
244ae115bc7Smrj  * Note that if va is in the middle of a large page, the returned va
245ae115bc7Smrj  * will be less than what was asked for.
246ae115bc7Smrj  */
247ae115bc7Smrj int
kbm_probe(uintptr_t * va,size_t * len,pfn_t * pfn,uint_t * prot)248ae115bc7Smrj kbm_probe(uintptr_t *va, size_t *len, pfn_t *pfn, uint_t *prot)
249ae115bc7Smrj {
250ae115bc7Smrj 	uintptr_t	probe_va;
251ae115bc7Smrj 	x86pte_t	*ptep;
252ae115bc7Smrj 	paddr_t		pte_physaddr;
253ae115bc7Smrj 	x86pte_t	pte_val;
254ae115bc7Smrj 	level_t		l;
255ae115bc7Smrj 
256ae115bc7Smrj 	if (khat_running)
257ae115bc7Smrj 		panic("kbm_probe() called too late");
258ae115bc7Smrj 	*len = 0;
259ae115bc7Smrj 	*pfn = PFN_INVALID;
260ae115bc7Smrj 	*prot = 0;
261ae115bc7Smrj 	probe_va = *va;
262ae115bc7Smrj restart_new_va:
263ae115bc7Smrj 	l = top_level;
264ae115bc7Smrj 	for (;;) {
265ae115bc7Smrj 		if (IN_VA_HOLE(probe_va))
266ae115bc7Smrj 			probe_va = mmu.hole_end;
267ae115bc7Smrj 
268ae115bc7Smrj 		if (IN_HYPERVISOR_VA(probe_va))
269843e1988Sjohnlev #if defined(__amd64) && defined(__xpv)
270843e1988Sjohnlev 			probe_va = HYPERVISOR_VIRT_END;
271843e1988Sjohnlev #else
272ae115bc7Smrj 			return (0);
273843e1988Sjohnlev #endif
274ae115bc7Smrj 
275ae115bc7Smrj 		/*
276ae115bc7Smrj 		 * If we don't have a valid PTP/PTE at this level
277ae115bc7Smrj 		 * then we can bump VA by this level's pagesize and try again.
278ae115bc7Smrj 		 * When the probe_va wraps around, we are done.
279ae115bc7Smrj 		 */
280ae115bc7Smrj 		ptep = find_pte(probe_va, &pte_physaddr, l, 1);
281ae115bc7Smrj 		if (ptep == NULL)
282ae115bc7Smrj 			bop_panic("kbm_probe: find_pte returned NULL");
283ae115bc7Smrj 		if (kbm_pae_support)
284ae115bc7Smrj 			pte_val = *ptep;
285ae115bc7Smrj 		else
286ae115bc7Smrj 			pte_val = *((x86pte32_t *)ptep);
287ae115bc7Smrj 		if (!PTE_ISVALID(pte_val)) {
288ae115bc7Smrj 			probe_va = (probe_va & BOOT_MASK(l)) + BOOT_SZ(l);
289ae115bc7Smrj 			if (probe_va <= *va)
290ae115bc7Smrj 				return (0);
291ae115bc7Smrj 			goto restart_new_va;
292ae115bc7Smrj 		}
293ae115bc7Smrj 
294ae115bc7Smrj 		/*
295ae115bc7Smrj 		 * If this entry is a pointer to a lower level page table
296ae115bc7Smrj 		 * go down to it.
297ae115bc7Smrj 		 */
298ae115bc7Smrj 		if (!PTE_ISPAGE(pte_val, l)) {
299ae115bc7Smrj 			ASSERT(l > 0);
300ae115bc7Smrj 			--l;
301ae115bc7Smrj 			continue;
302ae115bc7Smrj 		}
303ae115bc7Smrj 
304ae115bc7Smrj 		/*
305ae115bc7Smrj 		 * We found a boot level page table entry
306ae115bc7Smrj 		 */
307ae115bc7Smrj 		*len = BOOT_SZ(l);
308ae115bc7Smrj 		*va = probe_va & ~(*len - 1);
309ae115bc7Smrj 		*pfn = PTE2PFN(pte_val, l);
310ae115bc7Smrj 
311ae115bc7Smrj 
312ae115bc7Smrj 		*prot = PROT_READ | PROT_EXEC;
313ae115bc7Smrj 		if (PTE_GET(pte_val, PT_WRITABLE))
314ae115bc7Smrj 			*prot |= PROT_WRITE;
315ae115bc7Smrj 
316ae115bc7Smrj 		/*
317ae115bc7Smrj 		 * pt_nx is cleared if processor doesn't support NX bit
318ae115bc7Smrj 		 */
319ae115bc7Smrj 		if (PTE_GET(pte_val, mmu.pt_nx))
320ae115bc7Smrj 			*prot &= ~PROT_EXEC;
321ae115bc7Smrj 
322ae115bc7Smrj 		return (1);
323ae115bc7Smrj 	}
324ae115bc7Smrj }
325ae115bc7Smrj 
326ae115bc7Smrj 
327ae115bc7Smrj /*
328ae115bc7Smrj  * Destroy a boot loader page table 4K mapping.
329ae115bc7Smrj  */
330ae115bc7Smrj void
kbm_unmap(uintptr_t va)331ae115bc7Smrj kbm_unmap(uintptr_t va)
332ae115bc7Smrj {
333ae115bc7Smrj 	if (khat_running)
334ae115bc7Smrj 		panic("kbm_unmap() called too late");
335ae115bc7Smrj 	else {
336843e1988Sjohnlev #ifdef __xpv
337843e1988Sjohnlev 		(void) HYPERVISOR_update_va_mapping(va, 0,
338843e1988Sjohnlev 		    UVMF_INVLPG | UVMF_LOCAL);
339843e1988Sjohnlev #else
340ae115bc7Smrj 		x86pte_t *ptep;
341ae115bc7Smrj 		level_t	level = 0;
342ae115bc7Smrj 		uint_t  probe_only = 1;
343ae115bc7Smrj 
344ae115bc7Smrj 		ptep = find_pte(va, NULL, level, probe_only);
345ae115bc7Smrj 		if (ptep == NULL)
346ae115bc7Smrj 			return;
347ae115bc7Smrj 
348ae115bc7Smrj 		if (kbm_pae_support)
349ae115bc7Smrj 			*ptep = 0;
350ae115bc7Smrj 		else
351ae115bc7Smrj 			*((x86pte32_t *)ptep) = 0;
352ae115bc7Smrj 		mmu_tlbflush_entry((caddr_t)va);
353843e1988Sjohnlev #endif
354ae115bc7Smrj 	}
355ae115bc7Smrj }
356ae115bc7Smrj 
357ae115bc7Smrj 
358ae115bc7Smrj /*
359ae115bc7Smrj  * Change a boot loader page table 4K mapping.
360ae115bc7Smrj  * Returns the pfn of the old mapping.
361ae115bc7Smrj  */
362ae115bc7Smrj pfn_t
kbm_remap(uintptr_t va,pfn_t pfn)363ae115bc7Smrj kbm_remap(uintptr_t va, pfn_t pfn)
364ae115bc7Smrj {
365ae115bc7Smrj 	x86pte_t *ptep;
366ae115bc7Smrj 	level_t	level = 0;
367ae115bc7Smrj 	uint_t  probe_only = 1;
368ae115bc7Smrj 	x86pte_t pte_val = pa_to_ma(pfn_to_pa(pfn)) | PT_WRITABLE |
369ae115bc7Smrj 	    PT_NOCONSIST | PT_VALID;
370ae115bc7Smrj 	x86pte_t old_pte;
371ae115bc7Smrj 
372ae115bc7Smrj 	if (khat_running)
373ae115bc7Smrj 		panic("kbm_remap() called too late");
374ae115bc7Smrj 	ptep = find_pte(va, NULL, level, probe_only);
375ae115bc7Smrj 	if (ptep == NULL)
376ae115bc7Smrj 		bop_panic("kbm_remap: find_pte returned NULL");
377ae115bc7Smrj 
378ae115bc7Smrj 	if (kbm_pae_support)
379ae115bc7Smrj 		old_pte = *ptep;
380ae115bc7Smrj 	else
381ae115bc7Smrj 		old_pte = *((x86pte32_t *)ptep);
382ae115bc7Smrj 
383843e1988Sjohnlev #ifdef __xpv
384843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
385843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping() failed");
386843e1988Sjohnlev #else
387ae115bc7Smrj 	if (kbm_pae_support)
388ae115bc7Smrj 		*((x86pte_t *)ptep) = pte_val;
389ae115bc7Smrj 	else
390ae115bc7Smrj 		*((x86pte32_t *)ptep) = pte_val;
391ae115bc7Smrj 	mmu_tlbflush_entry((caddr_t)va);
392843e1988Sjohnlev #endif
393ae115bc7Smrj 
394ae115bc7Smrj 	if (!(old_pte & PT_VALID) || ma_to_pa(old_pte) == -1)
395ae115bc7Smrj 		return (PFN_INVALID);
396ae115bc7Smrj 	return (mmu_btop(ma_to_pa(old_pte)));
397ae115bc7Smrj }
398ae115bc7Smrj 
399ae115bc7Smrj 
400ae115bc7Smrj /*
401ae115bc7Smrj  * Change a boot loader page table 4K mapping to read only.
402ae115bc7Smrj  */
403ae115bc7Smrj void
kbm_read_only(uintptr_t va,paddr_t pa)404ae115bc7Smrj kbm_read_only(uintptr_t va, paddr_t pa)
405ae115bc7Smrj {
406ae115bc7Smrj 	x86pte_t pte_val = pa_to_ma(pa) |
407ae115bc7Smrj 	    PT_NOCONSIST | PT_REF | PT_MOD | PT_VALID;
408843e1988Sjohnlev 
409843e1988Sjohnlev #ifdef __xpv
410843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping(va, pte_val, UVMF_INVLPG | UVMF_LOCAL))
411843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping() failed");
412843e1988Sjohnlev #else
413ae115bc7Smrj 	x86pte_t *ptep;
414ae115bc7Smrj 	level_t	level = 0;
415ae115bc7Smrj 
416ae115bc7Smrj 	ptep = find_pte(va, NULL, level, 0);
417ae115bc7Smrj 	if (ptep == NULL)
418ae115bc7Smrj 		bop_panic("kbm_read_only: find_pte returned NULL");
419ae115bc7Smrj 
420ae115bc7Smrj 	if (kbm_pae_support)
421ae115bc7Smrj 		*ptep = pte_val;
422ae115bc7Smrj 	else
423ae115bc7Smrj 		*((x86pte32_t *)ptep) = pte_val;
424ae115bc7Smrj 	mmu_tlbflush_entry((caddr_t)va);
425843e1988Sjohnlev #endif
426ae115bc7Smrj }
427ae115bc7Smrj 
428ae115bc7Smrj /*
429ae115bc7Smrj  * interfaces for kernel debugger to access physical memory
430ae115bc7Smrj  */
431ae115bc7Smrj static x86pte_t save_pte;
432ae115bc7Smrj 
433ae115bc7Smrj void *
kbm_push(paddr_t pa)434ae115bc7Smrj kbm_push(paddr_t pa)
435ae115bc7Smrj {
436ae115bc7Smrj 	static int first_time = 1;
437ae115bc7Smrj 
438ae115bc7Smrj 	if (first_time) {
439ae115bc7Smrj 		first_time = 0;
440ae115bc7Smrj 		return (window);
441ae115bc7Smrj 	}
442ae115bc7Smrj 
443ae115bc7Smrj 	if (kbm_pae_support)
444ae115bc7Smrj 		save_pte = *((x86pte_t *)pte_to_window);
445ae115bc7Smrj 	else
446ae115bc7Smrj 		save_pte = *((x86pte32_t *)pte_to_window);
447ae115bc7Smrj 	return (kbm_remap_window(pa, 0));
448ae115bc7Smrj }
449ae115bc7Smrj 
450ae115bc7Smrj void
kbm_pop(void)451ae115bc7Smrj kbm_pop(void)
452ae115bc7Smrj {
453843e1988Sjohnlev #ifdef __xpv
454843e1988Sjohnlev 	if (HYPERVISOR_update_va_mapping((uintptr_t)window, save_pte,
455843e1988Sjohnlev 	    UVMF_INVLPG | UVMF_LOCAL) < 0)
456843e1988Sjohnlev 		bop_panic("HYPERVISOR_update_va_mapping() failed");
457843e1988Sjohnlev #else
458ae115bc7Smrj 	if (kbm_pae_support)
459ae115bc7Smrj 		*((x86pte_t *)pte_to_window) = save_pte;
460ae115bc7Smrj 	else
461ae115bc7Smrj 		*((x86pte32_t *)pte_to_window) = save_pte;
462ae115bc7Smrj 	mmu_tlbflush_entry(window);
463843e1988Sjohnlev #endif
464ae115bc7Smrj }
465ae115bc7Smrj 
466ae115bc7Smrj x86pte_t
get_pteval(paddr_t table,uint_t index)467ae115bc7Smrj get_pteval(paddr_t table, uint_t index)
468ae115bc7Smrj {
469ae115bc7Smrj 	void *table_ptr = kbm_remap_window(table, 0);
470ae115bc7Smrj 
471ae115bc7Smrj 	if (kbm_pae_support)
472ae115bc7Smrj 		return (((x86pte_t *)table_ptr)[index]);
473ae115bc7Smrj 	return (((x86pte32_t *)table_ptr)[index]);
474ae115bc7Smrj }
475ae115bc7Smrj 
476843e1988Sjohnlev #ifndef __xpv
477ae115bc7Smrj void
set_pteval(paddr_t table,uint_t index,uint_t level,x86pte_t pteval)478ae115bc7Smrj set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval)
479ae115bc7Smrj {
480ae115bc7Smrj 	void *table_ptr = kbm_remap_window(table, 0);
481ae115bc7Smrj 	if (kbm_pae_support)
482ae115bc7Smrj 		((x86pte_t *)table_ptr)[index] = pteval;
483ae115bc7Smrj 	else
484ae115bc7Smrj 		((x86pte32_t *)table_ptr)[index] = pteval;
485ae115bc7Smrj 	if (level == top_level && level == 2)
486ae115bc7Smrj 		reload_cr3();
487ae115bc7Smrj }
488843e1988Sjohnlev #endif
489ae115bc7Smrj 
490ae115bc7Smrj paddr_t
make_ptable(x86pte_t * pteval,uint_t level)491ae115bc7Smrj make_ptable(x86pte_t *pteval, uint_t level)
492ae115bc7Smrj {
493ae115bc7Smrj 	paddr_t new_table;
494ae115bc7Smrj 	void *table_ptr;
495ae115bc7Smrj 
496ae115bc7Smrj 	new_table = do_bop_phys_alloc(MMU_PAGESIZE, MMU_PAGESIZE);
497ae115bc7Smrj 	table_ptr = kbm_remap_window(new_table, 1);
498ae115bc7Smrj 	bzero(table_ptr, MMU_PAGESIZE);
499843e1988Sjohnlev #ifdef __xpv
500843e1988Sjohnlev 	/* Remove write permission to the new page table.  */
501843e1988Sjohnlev 	(void) kbm_remap_window(new_table, 0);
502843e1988Sjohnlev #endif
503ae115bc7Smrj 
504ae115bc7Smrj 	if (level == top_level && level == 2)
505ae115bc7Smrj 		*pteval = pa_to_ma(new_table) | PT_VALID;
506ae115bc7Smrj 	else
507ae115bc7Smrj 		*pteval = pa_to_ma(new_table) |
508ae115bc7Smrj 		    PT_VALID | PT_REF | PT_USER | PT_WRITABLE;
509ae115bc7Smrj 
510ae115bc7Smrj 	return (new_table);
511ae115bc7Smrj }
512ae115bc7Smrj 
513ae115bc7Smrj x86pte_t *
map_pte(paddr_t table,uint_t index)514ae115bc7Smrj map_pte(paddr_t table, uint_t index)
515ae115bc7Smrj {
516ae115bc7Smrj 	void *table_ptr = kbm_remap_window(table, 0);
517ae115bc7Smrj 	return ((x86pte_t *)((caddr_t)table_ptr + index * pte_size));
518ae115bc7Smrj }
519