xref: /illumos-gate/usr/src/uts/i86pc/boot/boot_mmu.c (revision 71815ce76261aa773c97600750fdce92334d1990)
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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * WARNING: This file is used by both dboot and the kernel.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/param.h>
34 #include <sys/machparam.h>
35 #include <sys/mach_mmu.h>
36 #ifdef __xpv
37 #include <sys/hypervisor.h>
38 #endif
39 
40 #ifdef _BOOT
41 #include <dboot/dboot_printf.h>
42 #define	bop_panic dboot_panic
43 #else
44 #include <sys/bootconf.h>
45 #endif
46 
47 uint_t shift_amt_nopae[] = {12, 22};
48 uint_t shift_amt_pae[] = {12, 21, 30, 39};
49 uint_t *shift_amt;
50 uint_t ptes_per_table;
51 uint_t pte_size;
52 uint32_t lpagesize;
53 paddr_t top_page_table;
54 uint_t top_level;
55 
56 /*
57  * Return the index corresponding to a virt address at a given page table level.
58  */
59 static uint_t
60 vatoindex(uint64_t va, uint_t level)
61 {
62 	return ((va >> shift_amt[level]) & (ptes_per_table - 1));
63 }
64 
65 /*
66  * Return a pointer to the page table entry that maps a virtual address.
67  * If there is no page table and probe_only is not set, one is created.
68  */
69 x86pte_t *
70 find_pte(uint64_t va, paddr_t *pa, uint_t level, uint_t probe_only)
71 {
72 	uint_t l;
73 	uint_t index;
74 	paddr_t table;
75 
76 	if (pa)
77 		*pa = 0;
78 
79 #ifndef _BOOT
80 	if (IN_HYPERVISOR_VA(va))
81 		return (NULL);
82 #endif
83 
84 	/*
85 	 * Walk down the page tables creating any needed intermediate tables.
86 	 */
87 	table = top_page_table;
88 	for (l = top_level; l != level; --l) {
89 		uint64_t pteval;
90 		paddr_t new_table;
91 
92 		index = vatoindex(va, l);
93 		pteval = get_pteval(table, index);
94 
95 		/*
96 		 * Life is easy if we find the pagetable.  We just use it.
97 		 */
98 		if (pteval & PT_VALID) {
99 			table = ma_to_pa(pteval & MMU_PAGEMASK);
100 			if (table == -1) {
101 				if (probe_only)
102 					return (NULL);
103 				bop_panic("find_pte(): phys not found!");
104 			}
105 			continue;
106 		}
107 
108 		if (probe_only)
109 			return (NULL);
110 
111 		new_table = make_ptable(&pteval, l);
112 		set_pteval(table, index, l, pteval);
113 
114 		table = new_table;
115 	}
116 
117 	/*
118 	 * Return a pointer into the current pagetable.
119 	 */
120 	index = vatoindex(va, l);
121 	if (pa)
122 		*pa = table + index * pte_size;
123 	return (map_pte(table, index));
124 }
125