| @@ -1,1899 +1,1898 @@ | | | @@ -1,1899 +1,1898 @@ |
1 | /* $NetBSD: pmap.c,v 1.83 2020/03/05 01:35:00 rin Exp $ */ | | 1 | /* $NetBSD: pmap.c,v 1.84 2020/03/05 02:14:52 rin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright 2001 Wasabi Systems, Inc. | | 4 | * Copyright 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. | | 7 | * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * 3. All advertising materials mentioning features or use of this software | | 17 | * 3. All advertising materials mentioning features or use of this software |
18 | * must display the following acknowledgement: | | 18 | * must display the following acknowledgement: |
19 | * This product includes software developed for the NetBSD Project by | | 19 | * This product includes software developed for the NetBSD Project by |
20 | * Wasabi Systems, Inc. | | 20 | * Wasabi Systems, Inc. |
21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse | | 21 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
22 | * or promote products derived from this software without specific prior | | 22 | * or promote products derived from this software without specific prior |
23 | * written permission. | | 23 | * written permission. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND | | 25 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | /* | | 38 | /* |
39 | * Copyright (C) 1995, 1996 Wolfgang Solfrank. | | 39 | * Copyright (C) 1995, 1996 Wolfgang Solfrank. |
40 | * Copyright (C) 1995, 1996 TooLs GmbH. | | 40 | * Copyright (C) 1995, 1996 TooLs GmbH. |
41 | * All rights reserved. | | 41 | * All rights reserved. |
42 | * | | 42 | * |
43 | * Redistribution and use in source and binary forms, with or without | | 43 | * Redistribution and use in source and binary forms, with or without |
44 | * modification, are permitted provided that the following conditions | | 44 | * modification, are permitted provided that the following conditions |
45 | * are met: | | 45 | * are met: |
46 | * 1. Redistributions of source code must retain the above copyright | | 46 | * 1. Redistributions of source code must retain the above copyright |
47 | * notice, this list of conditions and the following disclaimer. | | 47 | * notice, this list of conditions and the following disclaimer. |
48 | * 2. Redistributions in binary form must reproduce the above copyright | | 48 | * 2. Redistributions in binary form must reproduce the above copyright |
49 | * notice, this list of conditions and the following disclaimer in the | | 49 | * notice, this list of conditions and the following disclaimer in the |
50 | * documentation and/or other materials provided with the distribution. | | 50 | * documentation and/or other materials provided with the distribution. |
51 | * 3. All advertising materials mentioning features or use of this software | | 51 | * 3. All advertising materials mentioning features or use of this software |
52 | * must display the following acknowledgement: | | 52 | * must display the following acknowledgement: |
53 | * This product includes software developed by TooLs GmbH. | | 53 | * This product includes software developed by TooLs GmbH. |
54 | * 4. The name of TooLs GmbH may not be used to endorse or promote products | | 54 | * 4. The name of TooLs GmbH may not be used to endorse or promote products |
55 | * derived from this software without specific prior written permission. | | 55 | * derived from this software without specific prior written permission. |
56 | * | | 56 | * |
57 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR | | 57 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR |
58 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 58 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
59 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 59 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
60 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | | 60 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
61 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | | 61 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
62 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | | 62 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
63 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | | 63 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
64 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | | 64 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
65 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | | 65 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
66 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 66 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
67 | */ | | 67 | */ |
68 | | | 68 | |
69 | #include <sys/cdefs.h> | | 69 | #include <sys/cdefs.h> |
70 | __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.83 2020/03/05 01:35:00 rin Exp $"); | | 70 | __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.84 2020/03/05 02:14:52 rin Exp $"); |
71 | | | 71 | |
72 | #include <sys/param.h> | | 72 | #include <sys/param.h> |
73 | #include <sys/cpu.h> | | 73 | #include <sys/cpu.h> |
74 | #include <sys/device.h> | | 74 | #include <sys/device.h> |
75 | #include <sys/kmem.h> | | 75 | #include <sys/kmem.h> |
76 | #include <sys/pool.h> | | 76 | #include <sys/pool.h> |
77 | #include <sys/proc.h> | | 77 | #include <sys/proc.h> |
78 | #include <sys/queue.h> | | 78 | #include <sys/queue.h> |
79 | #include <sys/systm.h> | | 79 | #include <sys/systm.h> |
80 | | | 80 | |
81 | #include <uvm/uvm.h> | | 81 | #include <uvm/uvm.h> |
82 | | | 82 | |
83 | #include <machine/powerpc.h> | | 83 | #include <machine/powerpc.h> |
84 | #include <machine/tlb.h> | | 84 | #include <machine/tlb.h> |
85 | | | 85 | |
86 | #include <powerpc/pcb.h> | | 86 | #include <powerpc/pcb.h> |
87 | | | 87 | |
88 | #include <powerpc/spr.h> | | 88 | #include <powerpc/spr.h> |
89 | #include <powerpc/ibm4xx/spr.h> | | 89 | #include <powerpc/ibm4xx/spr.h> |
90 | | | 90 | |
91 | #include <powerpc/ibm4xx/cpu.h> | | 91 | #include <powerpc/ibm4xx/cpu.h> |
92 | | | 92 | |
93 | /* | | 93 | /* |
94 | * kernmap is an array of PTEs large enough to map in | | 94 | * kernmap is an array of PTEs large enough to map in |
95 | * 4GB. At 16KB/page it is 256K entries or 2MB. | | 95 | * 4GB. At 16KB/page it is 256K entries or 2MB. |
96 | */ | | 96 | */ |
97 | #define KERNMAP_SIZE ((0xffffffffU/PAGE_SIZE)+1) | | 97 | #define KERNMAP_SIZE ((0xffffffffU/PAGE_SIZE)+1) |
98 | void *kernmap; | | 98 | void *kernmap; |
99 | | | 99 | |
100 | #define MINCTX 2 | | 100 | #define MINCTX 2 |
101 | #define NUMCTX 256 | | 101 | #define NUMCTX 256 |
102 | | | 102 | |
103 | volatile struct pmap *ctxbusy[NUMCTX]; | | 103 | volatile struct pmap *ctxbusy[NUMCTX]; |
104 | | | 104 | |
105 | #define TLBF_USED 0x1 | | 105 | #define TLBF_USED 0x1 |
106 | #define TLBF_REF 0x2 | | 106 | #define TLBF_REF 0x2 |
107 | #define TLBF_LOCKED 0x4 | | 107 | #define TLBF_LOCKED 0x4 |
108 | #define TLB_LOCKED(i) (tlb_info[(i)].ti_flags & TLBF_LOCKED) | | 108 | #define TLB_LOCKED(i) (tlb_info[(i)].ti_flags & TLBF_LOCKED) |
109 | | | 109 | |
110 | typedef struct tlb_info_s { | | 110 | typedef struct tlb_info_s { |
111 | char ti_flags; | | 111 | char ti_flags; |
112 | char ti_ctx; /* TLB_PID assiciated with the entry */ | | 112 | char ti_ctx; /* TLB_PID assiciated with the entry */ |
113 | u_int ti_va; | | 113 | u_int ti_va; |
114 | } tlb_info_t; | | 114 | } tlb_info_t; |
115 | | | 115 | |
116 | volatile tlb_info_t tlb_info[NTLB]; | | 116 | volatile tlb_info_t tlb_info[NTLB]; |
117 | /* We'll use a modified FIFO replacement policy cause it's cheap */ | | 117 | /* We'll use a modified FIFO replacement policy cause it's cheap */ |
118 | volatile int tlbnext; | | 118 | volatile int tlbnext; |
119 | | | 119 | |
120 | static int tlb_nreserved = 0; | | 120 | static int tlb_nreserved = 0; |
121 | static int pmap_bootstrap_done = 0; | | 121 | static int pmap_bootstrap_done = 0; |
122 | | | 122 | |
123 | /* Event counters */ | | 123 | /* Event counters */ |
124 | struct evcnt tlbmiss_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, | | 124 | struct evcnt tlbmiss_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, |
125 | NULL, "cpu", "tlbmiss"); | | 125 | NULL, "cpu", "tlbmiss"); |
126 | struct evcnt tlbhit_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, | | 126 | struct evcnt tlbhit_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, |
127 | NULL, "cpu", "tlbhit"); | | 127 | NULL, "cpu", "tlbhit"); |
128 | struct evcnt tlbflush_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, | | 128 | struct evcnt tlbflush_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, |
129 | NULL, "cpu", "tlbflush"); | | 129 | NULL, "cpu", "tlbflush"); |
130 | struct evcnt tlbenter_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, | | 130 | struct evcnt tlbenter_ev = EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, |
131 | NULL, "cpu", "tlbenter"); | | 131 | NULL, "cpu", "tlbenter"); |
132 | EVCNT_ATTACH_STATIC(tlbmiss_ev); | | 132 | EVCNT_ATTACH_STATIC(tlbmiss_ev); |
133 | EVCNT_ATTACH_STATIC(tlbhit_ev); | | 133 | EVCNT_ATTACH_STATIC(tlbhit_ev); |
134 | EVCNT_ATTACH_STATIC(tlbflush_ev); | | 134 | EVCNT_ATTACH_STATIC(tlbflush_ev); |
135 | EVCNT_ATTACH_STATIC(tlbenter_ev); | | 135 | EVCNT_ATTACH_STATIC(tlbenter_ev); |
136 | | | 136 | |
137 | struct pmap kernel_pmap_; | | 137 | struct pmap kernel_pmap_; |
138 | struct pmap *const kernel_pmap_ptr = &kernel_pmap_; | | 138 | struct pmap *const kernel_pmap_ptr = &kernel_pmap_; |
139 | | | 139 | |
140 | static int npgs; | | 140 | static int npgs; |
141 | static u_int nextavail; | | 141 | static u_int nextavail; |
142 | #ifndef MSGBUFADDR | | 142 | #ifndef MSGBUFADDR |
143 | extern paddr_t msgbuf_paddr; | | 143 | extern paddr_t msgbuf_paddr; |
144 | #endif | | 144 | #endif |
145 | | | 145 | |
146 | static struct mem_region *mem, *avail; | | 146 | static struct mem_region *mem, *avail; |
147 | | | 147 | |
148 | /* | | 148 | /* |
149 | * This is a cache of referenced/modified bits. | | 149 | * This is a cache of referenced/modified bits. |
150 | * Bits herein are shifted by ATTRSHFT. | | 150 | * Bits herein are shifted by ATTRSHFT. |
151 | */ | | 151 | */ |
152 | static char *pmap_attrib; | | 152 | static char *pmap_attrib; |
153 | | | 153 | |
154 | #define PV_WIRED 0x1 | | 154 | #define PV_WIRED 0x1 |
155 | #define PV_WIRE(pv) ((pv)->pv_va |= PV_WIRED) | | 155 | #define PV_WIRE(pv) ((pv)->pv_va |= PV_WIRED) |
156 | #define PV_UNWIRE(pv) ((pv)->pv_va &= ~PV_WIRED) | | 156 | #define PV_UNWIRE(pv) ((pv)->pv_va &= ~PV_WIRED) |
157 | #define PV_ISWIRED(pv) ((pv)->pv_va & PV_WIRED) | | 157 | #define PV_ISWIRED(pv) ((pv)->pv_va & PV_WIRED) |
158 | #define PV_CMPVA(va,pv) (!(((pv)->pv_va ^ (va)) & (~PV_WIRED))) | | 158 | #define PV_CMPVA(va,pv) (!(((pv)->pv_va ^ (va)) & (~PV_WIRED))) |
159 | | | 159 | |
160 | struct pv_entry { | | 160 | struct pv_entry { |
161 | struct pv_entry *pv_next; /* Linked list of mappings */ | | 161 | struct pv_entry *pv_next; /* Linked list of mappings */ |
162 | struct pmap *pv_pm; | | 162 | struct pmap *pv_pm; |
163 | vaddr_t pv_va; /* virtual address of mapping */ | | 163 | vaddr_t pv_va; /* virtual address of mapping */ |
164 | }; | | 164 | }; |
165 | | | 165 | |
166 | /* Each index corresponds to TLB_SIZE_* value. */ | | 166 | /* Each index corresponds to TLB_SIZE_* value. */ |
167 | static size_t tlbsize[] = { | | 167 | static size_t tlbsize[] = { |
168 | 1024, /* TLB_SIZE_1K */ | | 168 | 1024, /* TLB_SIZE_1K */ |
169 | 4096, /* TLB_SIZE_4K */ | | 169 | 4096, /* TLB_SIZE_4K */ |
170 | 16384, /* TLB_SIZE_16K */ | | 170 | 16384, /* TLB_SIZE_16K */ |
171 | 65536, /* TLB_SIZE_64K */ | | 171 | 65536, /* TLB_SIZE_64K */ |
172 | 262144, /* TLB_SIZE_256K */ | | 172 | 262144, /* TLB_SIZE_256K */ |
173 | 1048576, /* TLB_SIZE_1M */ | | 173 | 1048576, /* TLB_SIZE_1M */ |
174 | 4194304, /* TLB_SIZE_4M */ | | 174 | 4194304, /* TLB_SIZE_4M */ |
175 | 16777216, /* TLB_SIZE_16M */ | | 175 | 16777216, /* TLB_SIZE_16M */ |
176 | }; | | 176 | }; |
177 | | | 177 | |
178 | struct pv_entry *pv_table; | | 178 | struct pv_entry *pv_table; |
179 | static struct pool pv_pool; | | 179 | static struct pool pv_pool; |
180 | | | 180 | |
181 | static int pmap_initialized; | | 181 | static int pmap_initialized; |
182 | | | 182 | |
183 | static int ctx_flush(int); | | 183 | static int ctx_flush(int); |
184 | | | 184 | |
185 | struct pv_entry *pa_to_pv(paddr_t); | | 185 | struct pv_entry *pa_to_pv(paddr_t); |
186 | static inline char *pa_to_attr(paddr_t); | | 186 | static inline char *pa_to_attr(paddr_t); |
187 | | | 187 | |
188 | static inline volatile u_int *pte_find(struct pmap *, vaddr_t); | | 188 | static inline volatile u_int *pte_find(struct pmap *, vaddr_t); |
189 | static inline int pte_enter(struct pmap *, vaddr_t, u_int); | | 189 | static inline int pte_enter(struct pmap *, vaddr_t, u_int); |
190 | | | 190 | |
191 | static inline int pmap_enter_pv(struct pmap *, vaddr_t, paddr_t, int); | | 191 | static inline int pmap_enter_pv(struct pmap *, vaddr_t, paddr_t, int); |
192 | static void pmap_remove_pv(struct pmap *, vaddr_t, paddr_t); | | 192 | static void pmap_remove_pv(struct pmap *, vaddr_t, paddr_t); |
193 | | | 193 | |
194 | static int ppc4xx_tlb_size_mask(size_t, int *, int *); | | 194 | static int ppc4xx_tlb_size_mask(size_t, int *, int *); |
195 | | | 195 | |
196 | | | 196 | |
197 | struct pv_entry * | | 197 | struct pv_entry * |
198 | pa_to_pv(paddr_t pa) | | 198 | pa_to_pv(paddr_t pa) |
199 | { | | 199 | { |
200 | uvm_physseg_t bank; | | 200 | uvm_physseg_t bank; |
201 | psize_t pg; | | 201 | psize_t pg; |
202 | | | 202 | |
203 | bank = uvm_physseg_find(atop(pa), &pg); | | 203 | bank = uvm_physseg_find(atop(pa), &pg); |
204 | if (bank == UVM_PHYSSEG_TYPE_INVALID) | | 204 | if (bank == UVM_PHYSSEG_TYPE_INVALID) |
205 | return NULL; | | 205 | return NULL; |
206 | return &uvm_physseg_get_pmseg(bank)->pvent[pg]; | | 206 | return &uvm_physseg_get_pmseg(bank)->pvent[pg]; |
207 | } | | 207 | } |
208 | | | 208 | |
209 | static inline char * | | 209 | static inline char * |
210 | pa_to_attr(paddr_t pa) | | 210 | pa_to_attr(paddr_t pa) |
211 | { | | 211 | { |
212 | uvm_physseg_t bank; | | 212 | uvm_physseg_t bank; |
213 | psize_t pg; | | 213 | psize_t pg; |
214 | | | 214 | |
215 | bank = uvm_physseg_find(atop(pa), &pg); | | 215 | bank = uvm_physseg_find(atop(pa), &pg); |
216 | if (bank == UVM_PHYSSEG_TYPE_INVALID) | | 216 | if (bank == UVM_PHYSSEG_TYPE_INVALID) |
217 | return NULL; | | 217 | return NULL; |
218 | return &uvm_physseg_get_pmseg(bank)->attrs[pg]; | | 218 | return &uvm_physseg_get_pmseg(bank)->attrs[pg]; |
219 | } | | 219 | } |
220 | | | 220 | |
221 | /* | | 221 | /* |
222 | * Insert PTE into page table. | | 222 | * Insert PTE into page table. |
223 | */ | | 223 | */ |
224 | int | | 224 | int |
225 | pte_enter(struct pmap *pm, vaddr_t va, u_int pte) | | 225 | pte_enter(struct pmap *pm, vaddr_t va, u_int pte) |
226 | { | | 226 | { |
227 | int seg = STIDX(va); | | 227 | int seg = STIDX(va); |
228 | int ptn = PTIDX(va); | | 228 | int ptn = PTIDX(va); |
229 | u_int oldpte; | | 229 | u_int oldpte; |
230 | | | 230 | |
231 | if (!pm->pm_ptbl[seg]) { | | 231 | if (!pm->pm_ptbl[seg]) { |
232 | /* Don't allocate a page to clear a non-existent mapping. */ | | 232 | /* Don't allocate a page to clear a non-existent mapping. */ |
233 | if (!pte) | | 233 | if (!pte) |
234 | return (0); | | 234 | return (0); |
235 | /* Allocate a page XXXX this will sleep! */ | | 235 | /* Allocate a page XXXX this will sleep! */ |
236 | pm->pm_ptbl[seg] = | | 236 | pm->pm_ptbl[seg] = |
237 | (uint *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, | | 237 | (uint *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
238 | UVM_KMF_WIRED | UVM_KMF_ZERO); | | 238 | UVM_KMF_WIRED | UVM_KMF_ZERO); |
239 | } | | 239 | } |
240 | oldpte = pm->pm_ptbl[seg][ptn]; | | 240 | oldpte = pm->pm_ptbl[seg][ptn]; |
241 | pm->pm_ptbl[seg][ptn] = pte; | | 241 | pm->pm_ptbl[seg][ptn] = pte; |
242 | | | 242 | |
243 | /* Flush entry. */ | | 243 | /* Flush entry. */ |
244 | ppc4xx_tlb_flush(va, pm->pm_ctx); | | 244 | ppc4xx_tlb_flush(va, pm->pm_ctx); |
245 | if (oldpte != pte) { | | 245 | if (oldpte != pte) { |
246 | if (pte == 0) | | 246 | if (pte == 0) |
247 | pm->pm_stats.resident_count--; | | 247 | pm->pm_stats.resident_count--; |
248 | else | | 248 | else |
249 | pm->pm_stats.resident_count++; | | 249 | pm->pm_stats.resident_count++; |
250 | } | | 250 | } |
251 | return (1); | | 251 | return (1); |
252 | } | | 252 | } |
253 | | | 253 | |
254 | /* | | 254 | /* |
255 | * Get a pointer to a PTE in a page table. | | 255 | * Get a pointer to a PTE in a page table. |
256 | */ | | 256 | */ |
257 | volatile u_int * | | 257 | volatile u_int * |
258 | pte_find(struct pmap *pm, vaddr_t va) | | 258 | pte_find(struct pmap *pm, vaddr_t va) |
259 | { | | 259 | { |
260 | int seg = STIDX(va); | | 260 | int seg = STIDX(va); |
261 | int ptn = PTIDX(va); | | 261 | int ptn = PTIDX(va); |
262 | | | 262 | |
263 | if (pm->pm_ptbl[seg]) | | 263 | if (pm->pm_ptbl[seg]) |
264 | return (&pm->pm_ptbl[seg][ptn]); | | 264 | return (&pm->pm_ptbl[seg][ptn]); |
265 | | | 265 | |
266 | return (NULL); | | 266 | return (NULL); |
267 | } | | 267 | } |
268 | | | 268 | |
269 | /* | | 269 | /* |
270 | * This is called during initppc, before the system is really initialized. | | 270 | * This is called during initppc, before the system is really initialized. |
271 | */ | | 271 | */ |
272 | void | | 272 | void |
273 | pmap_bootstrap(u_int kernelstart, u_int kernelend) | | 273 | pmap_bootstrap(u_int kernelstart, u_int kernelend) |
274 | { | | 274 | { |
275 | struct mem_region *mp, *mp1; | | 275 | struct mem_region *mp, *mp1; |
276 | int cnt, i; | | 276 | int cnt, i; |
277 | u_int s, e, sz; | | 277 | u_int s, e, sz; |
278 | | | 278 | |
279 | tlbnext = tlb_nreserved; | | 279 | tlbnext = tlb_nreserved; |
280 | | | 280 | |
281 | /* | | 281 | /* |
282 | * Allocate the kernel page table at the end of | | 282 | * Allocate the kernel page table at the end of |
283 | * kernel space so it's in the locked TTE. | | 283 | * kernel space so it's in the locked TTE. |
284 | */ | | 284 | */ |
285 | kernmap = (void *)kernelend; | | 285 | kernmap = (void *)kernelend; |
286 | | | 286 | |
287 | /* | | 287 | /* |
288 | * Initialize kernel page table. | | 288 | * Initialize kernel page table. |
289 | */ | | 289 | */ |
290 | for (i = 0; i < STSZ; i++) { | | 290 | for (i = 0; i < STSZ; i++) { |
291 | pmap_kernel()->pm_ptbl[i] = 0; | | 291 | pmap_kernel()->pm_ptbl[i] = 0; |
292 | } | | 292 | } |
293 | ctxbusy[0] = ctxbusy[1] = pmap_kernel(); | | 293 | ctxbusy[0] = ctxbusy[1] = pmap_kernel(); |
294 | | | 294 | |
295 | /* | | 295 | /* |
296 | * Announce page-size to the VM-system | | 296 | * Announce page-size to the VM-system |
297 | */ | | 297 | */ |
298 | uvmexp.pagesize = NBPG; | | 298 | uvmexp.pagesize = NBPG; |
299 | uvm_md_init(); | | 299 | uvm_md_init(); |
300 | | | 300 | |
301 | /* | | 301 | /* |
302 | * Get memory. | | 302 | * Get memory. |
303 | */ | | 303 | */ |
304 | mem_regions(&mem, &avail); | | 304 | mem_regions(&mem, &avail); |
305 | for (mp = mem; mp->size; mp++) { | | 305 | for (mp = mem; mp->size; mp++) { |
306 | physmem += btoc(mp->size); | | 306 | physmem += btoc(mp->size); |
307 | printf("+%lx,",mp->size); | | 307 | printf("+%lx,",mp->size); |
308 | } | | 308 | } |
309 | printf("\n"); | | 309 | printf("\n"); |
310 | ppc4xx_tlb_init(); | | 310 | ppc4xx_tlb_init(); |
311 | /* | | 311 | /* |
312 | * Count the number of available entries. | | 312 | * Count the number of available entries. |
313 | */ | | 313 | */ |
314 | for (cnt = 0, mp = avail; mp->size; mp++) | | 314 | for (cnt = 0, mp = avail; mp->size; mp++) |
315 | cnt++; | | 315 | cnt++; |
316 | | | 316 | |
317 | /* | | 317 | /* |
318 | * Page align all regions. | | 318 | * Page align all regions. |
319 | * Non-page aligned memory isn't very interesting to us. | | 319 | * Non-page aligned memory isn't very interesting to us. |
320 | * Also, sort the entries for ascending addresses. | | 320 | * Also, sort the entries for ascending addresses. |
321 | */ | | 321 | */ |
322 | kernelstart &= ~PGOFSET; | | 322 | kernelstart &= ~PGOFSET; |
323 | kernelend = (kernelend + PGOFSET) & ~PGOFSET; | | 323 | kernelend = (kernelend + PGOFSET) & ~PGOFSET; |
324 | for (mp = avail; mp->size; mp++) { | | 324 | for (mp = avail; mp->size; mp++) { |
325 | s = mp->start; | | 325 | s = mp->start; |
326 | e = mp->start + mp->size; | | 326 | e = mp->start + mp->size; |
327 | printf("%08x-%08x -> ",s,e); | | 327 | printf("%08x-%08x -> ",s,e); |
328 | /* | | 328 | /* |
329 | * Check whether this region holds all of the kernel. | | 329 | * Check whether this region holds all of the kernel. |
330 | */ | | 330 | */ |
331 | if (s < kernelstart && e > kernelend) { | | 331 | if (s < kernelstart && e > kernelend) { |
332 | avail[cnt].start = kernelend; | | 332 | avail[cnt].start = kernelend; |
333 | avail[cnt++].size = e - kernelend; | | 333 | avail[cnt++].size = e - kernelend; |
334 | e = kernelstart; | | 334 | e = kernelstart; |
335 | } | | 335 | } |
336 | /* | | 336 | /* |
337 | * Look whether this regions starts within the kernel. | | 337 | * Look whether this regions starts within the kernel. |
338 | */ | | 338 | */ |
339 | if (s >= kernelstart && s < kernelend) { | | 339 | if (s >= kernelstart && s < kernelend) { |
340 | if (e <= kernelend) | | 340 | if (e <= kernelend) |
341 | goto empty; | | 341 | goto empty; |
342 | s = kernelend; | | 342 | s = kernelend; |
343 | } | | 343 | } |
344 | /* | | 344 | /* |
345 | * Now look whether this region ends within the kernel. | | 345 | * Now look whether this region ends within the kernel. |
346 | */ | | 346 | */ |
347 | if (e > kernelstart && e <= kernelend) { | | 347 | if (e > kernelstart && e <= kernelend) { |
348 | if (s >= kernelstart) | | 348 | if (s >= kernelstart) |
349 | goto empty; | | 349 | goto empty; |
350 | e = kernelstart; | | 350 | e = kernelstart; |
351 | } | | 351 | } |
352 | /* | | 352 | /* |
353 | * Now page align the start and size of the region. | | 353 | * Now page align the start and size of the region. |
354 | */ | | 354 | */ |
355 | s = round_page(s); | | 355 | s = round_page(s); |
356 | e = trunc_page(e); | | 356 | e = trunc_page(e); |
357 | if (e < s) | | 357 | if (e < s) |
358 | e = s; | | 358 | e = s; |
359 | sz = e - s; | | 359 | sz = e - s; |
360 | printf("%08x-%08x = %x\n",s,e,sz); | | 360 | printf("%08x-%08x = %x\n",s,e,sz); |
361 | /* | | 361 | /* |
362 | * Check whether some memory is left here. | | 362 | * Check whether some memory is left here. |
363 | */ | | 363 | */ |
364 | if (sz == 0) { | | 364 | if (sz == 0) { |
365 | empty: | | 365 | empty: |
366 | memmove(mp, mp + 1, | | 366 | memmove(mp, mp + 1, |
367 | (cnt - (mp - avail)) * sizeof *mp); | | 367 | (cnt - (mp - avail)) * sizeof *mp); |
368 | cnt--; | | 368 | cnt--; |
369 | mp--; | | 369 | mp--; |
370 | continue; | | 370 | continue; |
371 | } | | 371 | } |
372 | /* | | 372 | /* |
373 | * Do an insertion sort. | | 373 | * Do an insertion sort. |
374 | */ | | 374 | */ |
375 | npgs += btoc(sz); | | 375 | npgs += btoc(sz); |
376 | for (mp1 = avail; mp1 < mp; mp1++) | | 376 | for (mp1 = avail; mp1 < mp; mp1++) |
377 | if (s < mp1->start) | | 377 | if (s < mp1->start) |
378 | break; | | 378 | break; |
379 | if (mp1 < mp) { | | 379 | if (mp1 < mp) { |
380 | memmove(mp1 + 1, mp1, (char *)mp - (char *)mp1); | | 380 | memmove(mp1 + 1, mp1, (char *)mp - (char *)mp1); |
381 | mp1->start = s; | | 381 | mp1->start = s; |
382 | mp1->size = sz; | | 382 | mp1->size = sz; |
383 | } else { | | 383 | } else { |
384 | mp->start = s; | | 384 | mp->start = s; |
385 | mp->size = sz; | | 385 | mp->size = sz; |
386 | } | | 386 | } |
387 | } | | 387 | } |
388 | | | 388 | |
389 | /* | | 389 | /* |
390 | * We cannot do pmap_steal_memory here, | | 390 | * We cannot do pmap_steal_memory here, |
391 | * since we don't run with translation enabled yet. | | 391 | * since we don't run with translation enabled yet. |
392 | */ | | 392 | */ |
393 | #ifndef MSGBUFADDR | | 393 | #ifndef MSGBUFADDR |
394 | /* | | 394 | /* |
395 | * allow for msgbuf | | 395 | * allow for msgbuf |
396 | */ | | 396 | */ |
397 | sz = round_page(MSGBUFSIZE); | | 397 | sz = round_page(MSGBUFSIZE); |
398 | mp = NULL; | | 398 | mp = NULL; |
399 | for (mp1 = avail; mp1->size; mp1++) | | 399 | for (mp1 = avail; mp1->size; mp1++) |
400 | if (mp1->size >= sz) | | 400 | if (mp1->size >= sz) |
401 | mp = mp1; | | 401 | mp = mp1; |
402 | if (mp == NULL) | | 402 | if (mp == NULL) |
403 | panic("not enough memory?"); | | 403 | panic("not enough memory?"); |
404 | | | 404 | |
405 | npgs -= btoc(sz); | | 405 | npgs -= btoc(sz); |
406 | msgbuf_paddr = mp->start + mp->size - sz; | | 406 | msgbuf_paddr = mp->start + mp->size - sz; |
407 | mp->size -= sz; | | 407 | mp->size -= sz; |
408 | if (mp->size <= 0) | | 408 | if (mp->size <= 0) |
409 | memmove(mp, mp + 1, (cnt - (mp - avail)) * sizeof *mp); | | 409 | memmove(mp, mp + 1, (cnt - (mp - avail)) * sizeof *mp); |
410 | #endif | | 410 | #endif |
411 | | | 411 | |
412 | for (mp = avail; mp->size; mp++) | | 412 | for (mp = avail; mp->size; mp++) |
413 | uvm_page_physload(atop(mp->start), atop(mp->start + mp->size), | | 413 | uvm_page_physload(atop(mp->start), atop(mp->start + mp->size), |
414 | atop(mp->start), atop(mp->start + mp->size), | | 414 | atop(mp->start), atop(mp->start + mp->size), |
415 | VM_FREELIST_DEFAULT); | | 415 | VM_FREELIST_DEFAULT); |
416 | | | 416 | |
417 | /* | | 417 | /* |
418 | * Initialize kernel pmap and hardware. | | 418 | * Initialize kernel pmap and hardware. |
419 | */ | | 419 | */ |
420 | /* Setup TLB pid allocator so it knows we alreadu using PID 1 */ | | 420 | /* Setup TLB pid allocator so it knows we alreadu using PID 1 */ |
421 | pmap_kernel()->pm_ctx = KERNEL_PID; | | 421 | pmap_kernel()->pm_ctx = KERNEL_PID; |
422 | nextavail = avail->start; | | 422 | nextavail = avail->start; |
423 | | | 423 | |
424 | pmap_bootstrap_done = 1; | | 424 | pmap_bootstrap_done = 1; |
425 | } | | 425 | } |
426 | | | 426 | |
427 | /* | | 427 | /* |
428 | * Restrict given range to physical memory | | 428 | * Restrict given range to physical memory |
429 | * | | 429 | * |
430 | * (Used by /dev/mem) | | 430 | * (Used by /dev/mem) |
431 | */ | | 431 | */ |
432 | void | | 432 | void |
433 | pmap_real_memory(paddr_t *start, psize_t *size) | | 433 | pmap_real_memory(paddr_t *start, psize_t *size) |
434 | { | | 434 | { |
435 | struct mem_region *mp; | | 435 | struct mem_region *mp; |
436 | | | 436 | |
437 | for (mp = mem; mp->size; mp++) { | | 437 | for (mp = mem; mp->size; mp++) { |
438 | if (*start + *size > mp->start && | | 438 | if (*start + *size > mp->start && |
439 | *start < mp->start + mp->size) { | | 439 | *start < mp->start + mp->size) { |
440 | if (*start < mp->start) { | | 440 | if (*start < mp->start) { |
441 | *size -= mp->start - *start; | | 441 | *size -= mp->start - *start; |
442 | *start = mp->start; | | 442 | *start = mp->start; |
443 | } | | 443 | } |
444 | if (*start + *size > mp->start + mp->size) | | 444 | if (*start + *size > mp->start + mp->size) |
445 | *size = mp->start + mp->size - *start; | | 445 | *size = mp->start + mp->size - *start; |
446 | return; | | 446 | return; |
447 | } | | 447 | } |
448 | } | | 448 | } |
449 | *size = 0; | | 449 | *size = 0; |
450 | } | | 450 | } |
451 | | | 451 | |
452 | /* | | 452 | /* |
453 | * Initialize anything else for pmap handling. | | 453 | * Initialize anything else for pmap handling. |
454 | * Called during vm_init(). | | 454 | * Called during vm_init(). |
455 | */ | | 455 | */ |
456 | void | | 456 | void |
457 | pmap_init(void) | | 457 | pmap_init(void) |
458 | { | | 458 | { |
459 | struct pv_entry *pv; | | 459 | struct pv_entry *pv; |
460 | vsize_t sz; | | 460 | vsize_t sz; |
461 | vaddr_t addr; | | 461 | vaddr_t addr; |
462 | int i, s; | | 462 | int i, s; |
463 | int bank; | | 463 | int bank; |
464 | char *attr; | | 464 | char *attr; |
465 | | | 465 | |
466 | sz = (vsize_t)((sizeof(struct pv_entry) + 1) * npgs); | | 466 | sz = (vsize_t)((sizeof(struct pv_entry) + 1) * npgs); |
467 | sz = round_page(sz); | | 467 | sz = round_page(sz); |
468 | addr = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED | UVM_KMF_ZERO); | | 468 | addr = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED | UVM_KMF_ZERO); |
469 | s = splvm(); | | 469 | s = splvm(); |
470 | pv = pv_table = (struct pv_entry *)addr; | | 470 | pv = pv_table = (struct pv_entry *)addr; |
471 | for (i = npgs; --i >= 0;) | | 471 | for (i = npgs; --i >= 0;) |
472 | pv++->pv_pm = NULL; | | 472 | pv++->pv_pm = NULL; |
473 | pmap_attrib = (char *)pv; | | 473 | pmap_attrib = (char *)pv; |
474 | memset(pv, 0, npgs); | | 474 | memset(pv, 0, npgs); |
475 | | | 475 | |
476 | pv = pv_table; | | 476 | pv = pv_table; |
477 | attr = pmap_attrib; | | 477 | attr = pmap_attrib; |
478 | for (bank = uvm_physseg_get_first(); | | 478 | for (bank = uvm_physseg_get_first(); |
479 | uvm_physseg_valid_p(bank); | | 479 | uvm_physseg_valid_p(bank); |
480 | bank = uvm_physseg_get_next(bank)) { | | 480 | bank = uvm_physseg_get_next(bank)) { |
481 | sz = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank); | | 481 | sz = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank); |
482 | uvm_physseg_get_pmseg(bank)->pvent = pv; | | 482 | uvm_physseg_get_pmseg(bank)->pvent = pv; |
483 | uvm_physseg_get_pmseg(bank)->attrs = attr; | | 483 | uvm_physseg_get_pmseg(bank)->attrs = attr; |
484 | pv += sz; | | 484 | pv += sz; |
485 | attr += sz; | | 485 | attr += sz; |
486 | } | | 486 | } |
487 | | | 487 | |
488 | pmap_initialized = 1; | | 488 | pmap_initialized = 1; |
489 | splx(s); | | 489 | splx(s); |
490 | | | 490 | |
491 | /* Setup a pool for additional pvlist structures */ | | 491 | /* Setup a pool for additional pvlist structures */ |
492 | pool_init(&pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pv_entry", NULL, | | 492 | pool_init(&pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pv_entry", NULL, |
493 | IPL_VM); | | 493 | IPL_VM); |
494 | } | | 494 | } |
495 | | | 495 | |
496 | /* | | 496 | /* |
497 | * How much virtual space is available to the kernel? | | 497 | * How much virtual space is available to the kernel? |
498 | */ | | 498 | */ |
499 | void | | 499 | void |
500 | pmap_virtual_space(vaddr_t *start, vaddr_t *end) | | 500 | pmap_virtual_space(vaddr_t *start, vaddr_t *end) |
501 | { | | 501 | { |
502 | | | 502 | |
503 | #if 0 | | 503 | #if 0 |
504 | /* | | 504 | /* |
505 | * Reserve one segment for kernel virtual memory | | 505 | * Reserve one segment for kernel virtual memory |
506 | */ | | 506 | */ |
507 | *start = (vaddr_t)(KERNEL_SR << ADDR_SR_SHFT); | | 507 | *start = (vaddr_t)(KERNEL_SR << ADDR_SR_SHFT); |
508 | *end = *start + SEGMENT_LENGTH; | | 508 | *end = *start + SEGMENT_LENGTH; |
509 | #else | | 509 | #else |
510 | *start = (vaddr_t) VM_MIN_KERNEL_ADDRESS; | | 510 | *start = (vaddr_t) VM_MIN_KERNEL_ADDRESS; |
511 | *end = (vaddr_t) VM_MAX_KERNEL_ADDRESS; | | 511 | *end = (vaddr_t) VM_MAX_KERNEL_ADDRESS; |
512 | #endif | | 512 | #endif |
513 | } | | 513 | } |
514 | | | 514 | |
515 | #ifdef PMAP_GROWKERNEL | | 515 | #ifdef PMAP_GROWKERNEL |
516 | /* | | 516 | /* |
517 | * Preallocate kernel page tables to a specified VA. | | 517 | * Preallocate kernel page tables to a specified VA. |
518 | * This simply loops through the first TTE for each | | 518 | * This simply loops through the first TTE for each |
519 | * page table from the beginning of the kernel pmap, | | 519 | * page table from the beginning of the kernel pmap, |
520 | * reads the entry, and if the result is | | 520 | * reads the entry, and if the result is |
521 | * zero (either invalid entry or no page table) it stores | | 521 | * zero (either invalid entry or no page table) it stores |
522 | * a zero there, populating page tables in the process. | | 522 | * a zero there, populating page tables in the process. |
523 | * This is not the most efficient technique but i don't | | 523 | * This is not the most efficient technique but i don't |
524 | * expect it to be called that often. | | 524 | * expect it to be called that often. |
525 | */ | | 525 | */ |
526 | extern struct vm_page *vm_page_alloc1(void); | | 526 | extern struct vm_page *vm_page_alloc1(void); |
527 | extern void vm_page_free1(struct vm_page *); | | 527 | extern void vm_page_free1(struct vm_page *); |
528 | | | 528 | |
529 | vaddr_t kbreak = VM_MIN_KERNEL_ADDRESS; | | 529 | vaddr_t kbreak = VM_MIN_KERNEL_ADDRESS; |
530 | | | 530 | |
531 | vaddr_t | | 531 | vaddr_t |
532 | pmap_growkernel(vaddr_t maxkvaddr) | | 532 | pmap_growkernel(vaddr_t maxkvaddr) |
533 | { | | 533 | { |
534 | int s; | | 534 | int s; |
535 | int seg; | | 535 | int seg; |
536 | paddr_t pg; | | 536 | paddr_t pg; |
537 | struct pmap *pm = pmap_kernel(); | | 537 | struct pmap *pm = pmap_kernel(); |
538 | | | 538 | |
539 | s = splvm(); | | 539 | s = splvm(); |
540 | | | 540 | |
541 | /* Align with the start of a page table */ | | 541 | /* Align with the start of a page table */ |
542 | for (kbreak &= ~(PTMAP-1); kbreak < maxkvaddr; | | 542 | for (kbreak &= ~(PTMAP-1); kbreak < maxkvaddr; |
543 | kbreak += PTMAP) { | | 543 | kbreak += PTMAP) { |
544 | seg = STIDX(kbreak); | | 544 | seg = STIDX(kbreak); |
545 | | | 545 | |
546 | if (pte_find(pm, kbreak)) | | 546 | if (pte_find(pm, kbreak)) |
547 | continue; | | 547 | continue; |
548 | | | 548 | |
549 | if (uvm.page_init_done) { | | 549 | if (uvm.page_init_done) { |
550 | pg = (paddr_t)VM_PAGE_TO_PHYS(vm_page_alloc1()); | | 550 | pg = (paddr_t)VM_PAGE_TO_PHYS(vm_page_alloc1()); |
551 | } else { | | 551 | } else { |
552 | if (!uvm_page_physget(&pg)) | | 552 | if (!uvm_page_physget(&pg)) |
553 | panic("pmap_growkernel: no memory"); | | 553 | panic("pmap_growkernel: no memory"); |
554 | } | | 554 | } |
555 | if (!pg) | | 555 | if (!pg) |
556 | panic("pmap_growkernel: no pages"); | | 556 | panic("pmap_growkernel: no pages"); |
557 | pmap_zero_page((paddr_t)pg); | | 557 | pmap_zero_page((paddr_t)pg); |
558 | | | 558 | |
559 | /* XXX This is based on all phymem being addressable */ | | 559 | /* XXX This is based on all phymem being addressable */ |
560 | pm->pm_ptbl[seg] = (u_int *)pg; | | 560 | pm->pm_ptbl[seg] = (u_int *)pg; |
561 | } | | 561 | } |
562 | splx(s); | | 562 | splx(s); |
563 | return (kbreak); | | 563 | return (kbreak); |
564 | } | | 564 | } |
565 | | | 565 | |
566 | /* | | 566 | /* |
567 | * vm_page_alloc1: | | 567 | * vm_page_alloc1: |
568 | * | | 568 | * |
569 | * Allocate and return a memory cell with no associated object. | | 569 | * Allocate and return a memory cell with no associated object. |
570 | */ | | 570 | */ |
571 | struct vm_page * | | 571 | struct vm_page * |
572 | vm_page_alloc1(void) | | 572 | vm_page_alloc1(void) |
573 | { | | 573 | { |
574 | struct vm_page *pg; | | 574 | struct vm_page *pg; |
575 | | | 575 | |
576 | pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE); | | 576 | pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE); |
577 | if (pg) { | | 577 | if (pg) { |
578 | pg->wire_count = 1; /* no mappings yet */ | | 578 | pg->wire_count = 1; /* no mappings yet */ |
579 | pg->flags &= ~PG_BUSY; /* never busy */ | | 579 | pg->flags &= ~PG_BUSY; /* never busy */ |
580 | } | | 580 | } |
581 | return pg; | | 581 | return pg; |
582 | } | | 582 | } |
583 | | | 583 | |
584 | /* | | 584 | /* |
585 | * vm_page_free1: | | 585 | * vm_page_free1: |
586 | * | | 586 | * |
587 | * Returns the given page to the free list, | | 587 | * Returns the given page to the free list, |
588 | * disassociating it with any VM object. | | 588 | * disassociating it with any VM object. |
589 | * | | 589 | * |
590 | * Object and page must be locked prior to entry. | | 590 | * Object and page must be locked prior to entry. |
591 | */ | | 591 | */ |
592 | void | | 592 | void |
593 | vm_page_free1(struct vm_page *pg) | | 593 | vm_page_free1(struct vm_page *pg) |
594 | { | | 594 | { |
595 | #ifdef DIAGNOSTIC | | 595 | #ifdef DIAGNOSTIC |
596 | if (pg->flags != (PG_CLEAN|PG_FAKE)) { | | 596 | if (pg->flags != (PG_CLEAN|PG_FAKE)) { |
597 | printf("Freeing invalid page %p\n", pg); | | 597 | printf("Freeing invalid page %p\n", pg); |
598 | printf("pa = %llx\n", (unsigned long long)VM_PAGE_TO_PHYS(pg)); | | 598 | printf("pa = %llx\n", (unsigned long long)VM_PAGE_TO_PHYS(pg)); |
599 | #ifdef DDB | | 599 | #ifdef DDB |
600 | Debugger(); | | 600 | Debugger(); |
601 | #endif | | 601 | #endif |
602 | return; | | 602 | return; |
603 | } | | 603 | } |
604 | #endif | | 604 | #endif |
605 | pg->flags |= PG_BUSY; | | 605 | pg->flags |= PG_BUSY; |
606 | pg->wire_count = 0; | | 606 | pg->wire_count = 0; |
607 | uvm_pagefree(pg); | | 607 | uvm_pagefree(pg); |
608 | } | | 608 | } |
609 | #endif | | 609 | #endif |
610 | | | 610 | |
611 | /* | | 611 | /* |
612 | * Create and return a physical map. | | 612 | * Create and return a physical map. |
613 | */ | | 613 | */ |
614 | struct pmap * | | 614 | struct pmap * |
615 | pmap_create(void) | | 615 | pmap_create(void) |
616 | { | | 616 | { |
617 | struct pmap *pm; | | 617 | struct pmap *pm; |
618 | | | 618 | |
619 | pm = kmem_alloc(sizeof(*pm), KM_SLEEP); | | 619 | pm = kmem_alloc(sizeof(*pm), KM_SLEEP); |
620 | memset(pm, 0, sizeof *pm); | | 620 | memset(pm, 0, sizeof *pm); |
621 | pm->pm_refs = 1; | | 621 | pm->pm_refs = 1; |
622 | return pm; | | 622 | return pm; |
623 | } | | 623 | } |
624 | | | 624 | |
625 | /* | | 625 | /* |
626 | * Add a reference to the given pmap. | | 626 | * Add a reference to the given pmap. |
627 | */ | | 627 | */ |
628 | void | | 628 | void |
629 | pmap_reference(struct pmap *pm) | | 629 | pmap_reference(struct pmap *pm) |
630 | { | | 630 | { |
631 | | | 631 | |
632 | pm->pm_refs++; | | 632 | pm->pm_refs++; |
633 | } | | 633 | } |
634 | | | 634 | |
635 | /* | | 635 | /* |
636 | * Retire the given pmap from service. | | 636 | * Retire the given pmap from service. |
637 | * Should only be called if the map contains no valid mappings. | | 637 | * Should only be called if the map contains no valid mappings. |
638 | */ | | 638 | */ |
639 | void | | 639 | void |
640 | pmap_destroy(struct pmap *pm) | | 640 | pmap_destroy(struct pmap *pm) |
641 | { | | 641 | { |
642 | int i; | | 642 | int i; |
643 | | | 643 | |
644 | if (--pm->pm_refs > 0) { | | 644 | if (--pm->pm_refs > 0) { |
645 | return; | | 645 | return; |
646 | } | | 646 | } |
647 | KASSERT(pm->pm_stats.resident_count == 0); | | 647 | KASSERT(pm->pm_stats.resident_count == 0); |
648 | KASSERT(pm->pm_stats.wired_count == 0); | | 648 | KASSERT(pm->pm_stats.wired_count == 0); |
649 | for (i = 0; i < STSZ; i++) | | 649 | for (i = 0; i < STSZ; i++) |
650 | if (pm->pm_ptbl[i]) { | | 650 | if (pm->pm_ptbl[i]) { |
651 | uvm_km_free(kernel_map, (vaddr_t)pm->pm_ptbl[i], | | 651 | uvm_km_free(kernel_map, (vaddr_t)pm->pm_ptbl[i], |
652 | PAGE_SIZE, UVM_KMF_WIRED); | | 652 | PAGE_SIZE, UVM_KMF_WIRED); |
653 | pm->pm_ptbl[i] = NULL; | | 653 | pm->pm_ptbl[i] = NULL; |
654 | } | | 654 | } |
655 | if (pm->pm_ctx) | | 655 | if (pm->pm_ctx) |
656 | ctx_free(pm); | | 656 | ctx_free(pm); |
657 | kmem_free(pm, sizeof(*pm)); | | 657 | kmem_free(pm, sizeof(*pm)); |
658 | } | | 658 | } |
659 | | | 659 | |
660 | /* | | 660 | /* |
661 | * Copy the range specified by src_addr/len | | 661 | * Copy the range specified by src_addr/len |
662 | * from the source map to the range dst_addr/len | | 662 | * from the source map to the range dst_addr/len |
663 | * in the destination map. | | 663 | * in the destination map. |
664 | * | | 664 | * |
665 | * This routine is only advisory and need not do anything. | | 665 | * This routine is only advisory and need not do anything. |
666 | */ | | 666 | */ |
667 | void | | 667 | void |
668 | pmap_copy(struct pmap *dst_pmap, struct pmap *src_pmap, vaddr_t dst_addr, | | 668 | pmap_copy(struct pmap *dst_pmap, struct pmap *src_pmap, vaddr_t dst_addr, |
669 | vsize_t len, vaddr_t src_addr) | | 669 | vsize_t len, vaddr_t src_addr) |
670 | { | | 670 | { |
671 | } | | 671 | } |
672 | | | 672 | |
673 | /* | | 673 | /* |
674 | * Require that all active physical maps contain no | | 674 | * Require that all active physical maps contain no |
675 | * incorrect entries NOW. | | 675 | * incorrect entries NOW. |
676 | */ | | 676 | */ |
677 | void | | 677 | void |
678 | pmap_update(struct pmap *pmap) | | 678 | pmap_update(struct pmap *pmap) |
679 | { | | 679 | { |
680 | } | | 680 | } |
681 | | | 681 | |
682 | /* | | 682 | /* |
683 | * Fill the given physical page with zeroes. | | 683 | * Fill the given physical page with zeroes. |
684 | */ | | 684 | */ |
685 | void | | 685 | void |
686 | pmap_zero_page(paddr_t pa) | | 686 | pmap_zero_page(paddr_t pa) |
687 | { | | 687 | { |
688 | | | 688 | |
689 | #ifdef PPC_4XX_NOCACHE | | 689 | #ifdef PPC_4XX_NOCACHE |
690 | memset((void *)pa, 0, PAGE_SIZE); | | 690 | memset((void *)pa, 0, PAGE_SIZE); |
691 | #else | | 691 | #else |
692 | int i; | | 692 | int i; |
693 | | | 693 | |
694 | for (i = PAGE_SIZE/CACHELINESIZE; i > 0; i--) { | | 694 | for (i = PAGE_SIZE/CACHELINESIZE; i > 0; i--) { |
695 | __asm volatile ("dcbz 0,%0" :: "r"(pa)); | | 695 | __asm volatile ("dcbz 0,%0" :: "r"(pa)); |
696 | pa += CACHELINESIZE; | | 696 | pa += CACHELINESIZE; |
697 | } | | 697 | } |
698 | #endif | | 698 | #endif |
699 | } | | 699 | } |
700 | | | 700 | |
701 | /* | | 701 | /* |
702 | * Copy the given physical source page to its destination. | | 702 | * Copy the given physical source page to its destination. |
703 | */ | | 703 | */ |
704 | void | | 704 | void |
705 | pmap_copy_page(paddr_t src, paddr_t dst) | | 705 | pmap_copy_page(paddr_t src, paddr_t dst) |
706 | { | | 706 | { |
707 | | | 707 | |
708 | memcpy((void *)dst, (void *)src, PAGE_SIZE); | | 708 | memcpy((void *)dst, (void *)src, PAGE_SIZE); |
709 | dcache_wbinv_page(dst); | | 709 | dcache_wbinv_page(dst); |
710 | } | | 710 | } |
711 | | | 711 | |
712 | /* | | 712 | /* |
713 | * This returns != 0 on success. | | 713 | * This returns != 0 on success. |
714 | */ | | 714 | */ |
715 | static inline int | | 715 | static inline int |
716 | pmap_enter_pv(struct pmap *pm, vaddr_t va, paddr_t pa, int flags) | | 716 | pmap_enter_pv(struct pmap *pm, vaddr_t va, paddr_t pa, int flags) |
717 | { | | 717 | { |
718 | struct pv_entry *pv, *npv = NULL; | | 718 | struct pv_entry *pv, *npv = NULL; |
719 | int s; | | 719 | int s; |
720 | | | 720 | |
721 | if (!pmap_initialized) | | 721 | if (!pmap_initialized) |
722 | return 0; | | 722 | return 0; |
723 | | | 723 | |
724 | s = splvm(); | | 724 | s = splvm(); |
725 | pv = pa_to_pv(pa); | | 725 | pv = pa_to_pv(pa); |
726 | if (!pv->pv_pm) { | | 726 | if (!pv->pv_pm) { |
727 | /* | | 727 | /* |
728 | * No entries yet, use header as the first entry. | | 728 | * No entries yet, use header as the first entry. |
729 | */ | | 729 | */ |
730 | pv->pv_va = va; | | 730 | pv->pv_va = va; |
731 | pv->pv_pm = pm; | | 731 | pv->pv_pm = pm; |
732 | pv->pv_next = NULL; | | 732 | pv->pv_next = NULL; |
733 | } else { | | 733 | } else { |
734 | /* | | 734 | /* |
735 | * There is at least one other VA mapping this page. | | 735 | * There is at least one other VA mapping this page. |
736 | * Place this entry after the header. | | 736 | * Place this entry after the header. |
737 | */ | | 737 | */ |
738 | npv = pool_get(&pv_pool, PR_NOWAIT); | | 738 | npv = pool_get(&pv_pool, PR_NOWAIT); |
739 | if (npv == NULL) { | | 739 | if (npv == NULL) { |
740 | if ((flags & PMAP_CANFAIL) == 0) | | 740 | if ((flags & PMAP_CANFAIL) == 0) |
741 | panic("pmap_enter_pv: failed"); | | 741 | panic("pmap_enter_pv: failed"); |
742 | splx(s); | | 742 | splx(s); |
743 | return 0; | | 743 | return 0; |
744 | } | | 744 | } |
745 | npv->pv_va = va; | | 745 | npv->pv_va = va; |
746 | npv->pv_pm = pm; | | 746 | npv->pv_pm = pm; |
747 | npv->pv_next = pv->pv_next; | | 747 | npv->pv_next = pv->pv_next; |
748 | pv->pv_next = npv; | | 748 | pv->pv_next = npv; |
749 | pv = npv; | | 749 | pv = npv; |
750 | } | | 750 | } |
751 | if (flags & PMAP_WIRED) { | | 751 | if (flags & PMAP_WIRED) { |
752 | PV_WIRE(pv); | | 752 | PV_WIRE(pv); |
753 | pm->pm_stats.wired_count++; | | 753 | pm->pm_stats.wired_count++; |
754 | } | | 754 | } |
755 | splx(s); | | 755 | splx(s); |
756 | return (1); | | 756 | return (1); |
757 | } | | 757 | } |
758 | | | 758 | |
759 | static void | | 759 | static void |
760 | pmap_remove_pv(struct pmap *pm, vaddr_t va, paddr_t pa) | | 760 | pmap_remove_pv(struct pmap *pm, vaddr_t va, paddr_t pa) |
761 | { | | 761 | { |
762 | struct pv_entry *pv, *npv; | | 762 | struct pv_entry *pv, *npv; |
763 | | | 763 | |
764 | /* | | 764 | /* |
765 | * Remove from the PV table. | | 765 | * Remove from the PV table. |
766 | */ | | 766 | */ |
767 | pv = pa_to_pv(pa); | | 767 | pv = pa_to_pv(pa); |
768 | if (!pv) | | 768 | if (!pv) |
769 | return; | | 769 | return; |
770 | | | 770 | |
771 | /* | | 771 | /* |
772 | * If it is the first entry on the list, it is actually | | 772 | * If it is the first entry on the list, it is actually |
773 | * in the header and we must copy the following entry up | | 773 | * in the header and we must copy the following entry up |
774 | * to the header. Otherwise we must search the list for | | 774 | * to the header. Otherwise we must search the list for |
775 | * the entry. In either case we free the now unused entry. | | 775 | * the entry. In either case we free the now unused entry. |
776 | */ | | 776 | */ |
777 | if (pm == pv->pv_pm && PV_CMPVA(va, pv)) { | | 777 | if (pm == pv->pv_pm && PV_CMPVA(va, pv)) { |
778 | if (PV_ISWIRED(pv)) { | | 778 | if (PV_ISWIRED(pv)) { |
779 | pm->pm_stats.wired_count--; | | 779 | pm->pm_stats.wired_count--; |
780 | } | | 780 | } |
781 | if ((npv = pv->pv_next)) { | | 781 | if ((npv = pv->pv_next)) { |
782 | *pv = *npv; | | 782 | *pv = *npv; |
783 | pool_put(&pv_pool, npv); | | 783 | pool_put(&pv_pool, npv); |
784 | } else | | 784 | } else |
785 | pv->pv_pm = NULL; | | 785 | pv->pv_pm = NULL; |
786 | } else { | | 786 | } else { |
787 | for (; (npv = pv->pv_next) != NULL; pv = npv) | | 787 | for (; (npv = pv->pv_next) != NULL; pv = npv) |
788 | if (pm == npv->pv_pm && PV_CMPVA(va, npv)) | | 788 | if (pm == npv->pv_pm && PV_CMPVA(va, npv)) |
789 | break; | | 789 | break; |
790 | if (npv) { | | 790 | if (npv) { |
791 | pv->pv_next = npv->pv_next; | | 791 | pv->pv_next = npv->pv_next; |
792 | if (PV_ISWIRED(npv)) { | | 792 | if (PV_ISWIRED(npv)) { |
793 | pm->pm_stats.wired_count--; | | 793 | pm->pm_stats.wired_count--; |
794 | } | | 794 | } |
795 | pool_put(&pv_pool, npv); | | 795 | pool_put(&pv_pool, npv); |
796 | } | | 796 | } |
797 | } | | 797 | } |
798 | } | | 798 | } |
799 | | | 799 | |
800 | /* | | 800 | /* |
801 | * Insert physical page at pa into the given pmap at virtual address va. | | 801 | * Insert physical page at pa into the given pmap at virtual address va. |
802 | */ | | 802 | */ |
803 | int | | 803 | int |
804 | pmap_enter(struct pmap *pm, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) | | 804 | pmap_enter(struct pmap *pm, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) |
805 | { | | 805 | { |
806 | int s; | | 806 | int s; |
807 | u_int tte; | | 807 | u_int tte; |
808 | bool managed; | | 808 | bool managed; |
809 | | | 809 | |
810 | /* | | 810 | /* |
811 | * Have to remove any existing mapping first. | | 811 | * Have to remove any existing mapping first. |
812 | */ | | 812 | */ |
813 | pmap_remove(pm, va, va + PAGE_SIZE); | | 813 | pmap_remove(pm, va, va + PAGE_SIZE); |
814 | | | 814 | |
815 | if (flags & PMAP_WIRED) | | 815 | if (flags & PMAP_WIRED) |
816 | flags |= prot; | | 816 | flags |= prot; |
817 | | | 817 | |
818 | managed = uvm_pageismanaged(pa); | | 818 | managed = uvm_pageismanaged(pa); |
819 | | | 819 | |
820 | /* | | 820 | /* |
821 | * Generate TTE. | | 821 | * Generate TTE. |
822 | */ | | 822 | */ |
823 | tte = TTE_PA(pa); | | 823 | tte = TTE_PA(pa); |
824 | /* XXXX -- need to support multiple page sizes. */ | | 824 | /* XXXX -- need to support multiple page sizes. */ |
825 | tte |= TTE_SZ_16K; | | 825 | tte |= TTE_SZ_16K; |
826 | #ifdef DIAGNOSTIC | | 826 | #ifdef DIAGNOSTIC |
827 | if ((flags & (PMAP_NOCACHE | PME_WRITETHROUG)) == | | 827 | if ((flags & (PMAP_NOCACHE | PME_WRITETHROUG)) == |
828 | (PMAP_NOCACHE | PME_WRITETHROUG)) | | 828 | (PMAP_NOCACHE | PME_WRITETHROUG)) |
829 | panic("pmap_enter: uncached & writethrough"); | | 829 | panic("pmap_enter: uncached & writethrough"); |
830 | #endif | | 830 | #endif |
831 | if (flags & PMAP_NOCACHE) | | 831 | if (flags & PMAP_NOCACHE) |
832 | /* Must be I/O mapping */ | | 832 | /* Must be I/O mapping */ |
833 | tte |= TTE_I | TTE_G; | | 833 | tte |= TTE_I | TTE_G; |
834 | #ifdef PPC_4XX_NOCACHE | | 834 | #ifdef PPC_4XX_NOCACHE |
835 | tte |= TTE_I; | | 835 | tte |= TTE_I; |
836 | #else | | 836 | #else |
837 | else if (flags & PME_WRITETHROUG) | | 837 | else if (flags & PME_WRITETHROUG) |
838 | /* Uncached and writethrough are not compatible */ | | 838 | /* Uncached and writethrough are not compatible */ |
839 | tte |= TTE_W; | | 839 | tte |= TTE_W; |
840 | #endif | | 840 | #endif |
841 | if (pm == pmap_kernel()) | | 841 | if (pm == pmap_kernel()) |
842 | tte |= TTE_ZONE(ZONE_PRIV); | | 842 | tte |= TTE_ZONE(ZONE_PRIV); |
843 | else | | 843 | else |
844 | tte |= TTE_ZONE(ZONE_USER); | | 844 | tte |= TTE_ZONE(ZONE_USER); |
845 | | | 845 | |
846 | if (flags & VM_PROT_WRITE) | | 846 | if (flags & VM_PROT_WRITE) |
847 | tte |= TTE_WR; | | 847 | tte |= TTE_WR; |
848 | | | 848 | |
849 | if (flags & VM_PROT_EXECUTE) | | 849 | if (flags & VM_PROT_EXECUTE) |
850 | tte |= TTE_EX; | | 850 | tte |= TTE_EX; |
851 | | | 851 | |
852 | /* | | 852 | /* |
853 | * Now record mapping for later back-translation. | | 853 | * Now record mapping for later back-translation. |
854 | */ | | 854 | */ |
855 | if (pmap_initialized && managed) { | | 855 | if (pmap_initialized && managed) { |
856 | char *attr; | | 856 | char *attr; |
857 | | | 857 | |
858 | if (!pmap_enter_pv(pm, va, pa, flags)) { | | 858 | if (!pmap_enter_pv(pm, va, pa, flags)) { |
859 | /* Could not enter pv on a managed page */ | | 859 | /* Could not enter pv on a managed page */ |
860 | return 1; | | 860 | return 1; |
861 | } | | 861 | } |
862 | | | 862 | |
863 | /* Now set attributes. */ | | 863 | /* Now set attributes. */ |
864 | attr = pa_to_attr(pa); | | 864 | attr = pa_to_attr(pa); |
865 | #ifdef DIAGNOSTIC | | 865 | #ifdef DIAGNOSTIC |
866 | if (!attr) | | 866 | if (!attr) |
867 | panic("managed but no attr"); | | 867 | panic("managed but no attr"); |
868 | #endif | | 868 | #endif |
869 | if (flags & VM_PROT_ALL) | | 869 | if (flags & VM_PROT_ALL) |
870 | *attr |= PMAP_ATTR_REF; | | 870 | *attr |= PMAP_ATTR_REF; |
871 | if (flags & VM_PROT_WRITE) | | 871 | if (flags & VM_PROT_WRITE) |
872 | *attr |= PMAP_ATTR_CHG; | | 872 | *attr |= PMAP_ATTR_CHG; |
873 | } | | 873 | } |
874 | | | 874 | |
875 | s = splvm(); | | 875 | s = splvm(); |
876 | | | 876 | |
877 | /* Insert page into page table. */ | | 877 | /* Insert page into page table. */ |
878 | pte_enter(pm, va, tte); | | 878 | pte_enter(pm, va, tte); |
879 | | | 879 | |
880 | /* If this is a real fault, enter it in the tlb */ | | 880 | /* If this is a real fault, enter it in the tlb */ |
881 | if (tte && ((flags & PMAP_WIRED) == 0)) { | | 881 | if (tte && ((flags & PMAP_WIRED) == 0)) { |
882 | int s2 = splhigh(); | | 882 | int s2 = splhigh(); |
883 | ppc4xx_tlb_enter(pm->pm_ctx, va, tte); | | 883 | ppc4xx_tlb_enter(pm->pm_ctx, va, tte); |
884 | splx(s2); | | 884 | splx(s2); |
885 | } | | 885 | } |
886 | splx(s); | | 886 | splx(s); |
887 | | | 887 | |
888 | /* Flush the real memory from the instruction cache. */ | | 888 | /* Flush the real memory from the instruction cache. */ |
889 | if ((prot & VM_PROT_EXECUTE) && (tte & TTE_I) == 0) | | 889 | if ((prot & VM_PROT_EXECUTE) && (tte & TTE_I) == 0) |
890 | __syncicache((void *)pa, PAGE_SIZE); | | 890 | __syncicache((void *)pa, PAGE_SIZE); |
891 | | | 891 | |
892 | return 0; | | 892 | return 0; |
893 | } | | 893 | } |
894 | | | 894 | |
895 | void | | 895 | void |
896 | pmap_unwire(struct pmap *pm, vaddr_t va) | | 896 | pmap_unwire(struct pmap *pm, vaddr_t va) |
897 | { | | 897 | { |
898 | struct pv_entry *pv; | | 898 | struct pv_entry *pv; |
899 | paddr_t pa; | | 899 | paddr_t pa; |
900 | int s; | | 900 | int s; |
901 | | | 901 | |
902 | if (!pmap_extract(pm, va, &pa)) { | | 902 | if (!pmap_extract(pm, va, &pa)) { |
903 | return; | | 903 | return; |
904 | } | | 904 | } |
905 | | | 905 | |
906 | pv = pa_to_pv(pa); | | 906 | pv = pa_to_pv(pa); |
907 | if (!pv) | | 907 | if (!pv) |
908 | return; | | 908 | return; |
909 | | | 909 | |
910 | s = splvm(); | | 910 | s = splvm(); |
911 | while (pv != NULL) { | | 911 | while (pv != NULL) { |
912 | if (pm == pv->pv_pm && PV_CMPVA(va, pv)) { | | 912 | if (pm == pv->pv_pm && PV_CMPVA(va, pv)) { |
913 | if (PV_ISWIRED(pv)) { | | 913 | if (PV_ISWIRED(pv)) { |
914 | PV_UNWIRE(pv); | | 914 | PV_UNWIRE(pv); |
915 | pm->pm_stats.wired_count--; | | 915 | pm->pm_stats.wired_count--; |
916 | } | | 916 | } |
917 | break; | | 917 | break; |
918 | } | | 918 | } |
919 | pv = pv->pv_next; | | 919 | pv = pv->pv_next; |
920 | } | | 920 | } |
921 | splx(s); | | 921 | splx(s); |
922 | } | | 922 | } |
923 | | | 923 | |
924 | void | | 924 | void |
925 | pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) | | 925 | pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) |
926 | { | | 926 | { |
927 | int s; | | 927 | int s; |
928 | u_int tte; | | 928 | u_int tte; |
929 | struct pmap *pm = pmap_kernel(); | | 929 | struct pmap *pm = pmap_kernel(); |
930 | | | 930 | |
931 | /* | | 931 | /* |
932 | * Have to remove any existing mapping first. | | 932 | * Have to remove any existing mapping first. |
933 | */ | | 933 | */ |
934 | | | 934 | |
935 | /* | | 935 | /* |
936 | * Generate TTE. | | 936 | * Generate TTE. |
937 | * | | 937 | * |
938 | * XXXX | | 938 | * XXXX |
939 | * | | 939 | * |
940 | * Since the kernel does not handle execution privileges properly, | | 940 | * Since the kernel does not handle execution privileges properly, |
941 | * we will handle read and execute permissions together. | | 941 | * we will handle read and execute permissions together. |
942 | */ | | 942 | */ |
943 | tte = 0; | | 943 | tte = 0; |
944 | if (prot & VM_PROT_ALL) { | | 944 | if (prot & VM_PROT_ALL) { |
945 | | | 945 | |
946 | tte = TTE_PA(pa) | TTE_EX | TTE_ZONE(ZONE_PRIV); | | 946 | tte = TTE_PA(pa) | TTE_EX | TTE_ZONE(ZONE_PRIV); |
947 | /* XXXX -- need to support multiple page sizes. */ | | 947 | /* XXXX -- need to support multiple page sizes. */ |
948 | tte |= TTE_SZ_16K; | | 948 | tte |= TTE_SZ_16K; |
949 | #ifdef DIAGNOSTIC | | 949 | #ifdef DIAGNOSTIC |
950 | if ((flags & (PMAP_NOCACHE | PME_WRITETHROUG)) == | | 950 | if ((flags & (PMAP_NOCACHE | PME_WRITETHROUG)) == |
951 | (PMAP_NOCACHE | PME_WRITETHROUG)) | | 951 | (PMAP_NOCACHE | PME_WRITETHROUG)) |
952 | panic("pmap_kenter_pa: uncached & writethrough"); | | 952 | panic("pmap_kenter_pa: uncached & writethrough"); |
953 | #endif | | 953 | #endif |
954 | if (flags & PMAP_NOCACHE) | | 954 | if (flags & PMAP_NOCACHE) |
955 | /* Must be I/O mapping */ | | 955 | /* Must be I/O mapping */ |
956 | tte |= TTE_I | TTE_G; | | 956 | tte |= TTE_I | TTE_G; |
957 | #ifdef PPC_4XX_NOCACHE | | 957 | #ifdef PPC_4XX_NOCACHE |
958 | tte |= TTE_I; | | 958 | tte |= TTE_I; |
959 | #else | | 959 | #else |
960 | else if (prot & PME_WRITETHROUG) | | 960 | else if (prot & PME_WRITETHROUG) |
961 | /* Uncached and writethrough are not compatible */ | | 961 | /* Uncached and writethrough are not compatible */ |
962 | tte |= TTE_W; | | 962 | tte |= TTE_W; |
963 | #endif | | 963 | #endif |
964 | if (prot & VM_PROT_WRITE) | | 964 | if (prot & VM_PROT_WRITE) |
965 | tte |= TTE_WR; | | 965 | tte |= TTE_WR; |
966 | } | | 966 | } |
967 | | | 967 | |
968 | s = splvm(); | | 968 | s = splvm(); |
969 | | | 969 | |
970 | /* Insert page into page table. */ | | 970 | /* Insert page into page table. */ |
971 | pte_enter(pm, va, tte); | | 971 | pte_enter(pm, va, tte); |
972 | splx(s); | | 972 | splx(s); |
973 | } | | 973 | } |
974 | | | 974 | |
975 | void | | 975 | void |
976 | pmap_kremove(vaddr_t va, vsize_t len) | | 976 | pmap_kremove(vaddr_t va, vsize_t len) |
977 | { | | 977 | { |
978 | | | 978 | |
979 | while (len > 0) { | | 979 | while (len > 0) { |
980 | pte_enter(pmap_kernel(), va, 0); | | 980 | pte_enter(pmap_kernel(), va, 0); |
981 | va += PAGE_SIZE; | | 981 | va += PAGE_SIZE; |
982 | len -= PAGE_SIZE; | | 982 | len -= PAGE_SIZE; |
983 | } | | 983 | } |
984 | } | | 984 | } |
985 | | | 985 | |
986 | /* | | 986 | /* |
987 | * Remove the given range of mapping entries. | | 987 | * Remove the given range of mapping entries. |
988 | */ | | 988 | */ |
989 | void | | 989 | void |
990 | pmap_remove(struct pmap *pm, vaddr_t va, vaddr_t endva) | | 990 | pmap_remove(struct pmap *pm, vaddr_t va, vaddr_t endva) |
991 | { | | 991 | { |
992 | int s; | | 992 | int s; |
993 | paddr_t pa; | | 993 | paddr_t pa; |
994 | volatile u_int *ptp; | | 994 | volatile u_int *ptp; |
995 | | | 995 | |
996 | s = splvm(); | | 996 | s = splvm(); |
997 | while (va < endva) { | | 997 | while (va < endva) { |
998 | | | 998 | |
999 | if ((ptp = pte_find(pm, va)) && (pa = *ptp)) { | | 999 | if ((ptp = pte_find(pm, va)) && (pa = *ptp)) { |
1000 | pa = TTE_PA(pa); | | 1000 | pa = TTE_PA(pa); |
1001 | pmap_remove_pv(pm, va, pa); | | 1001 | pmap_remove_pv(pm, va, pa); |
1002 | *ptp = 0; | | 1002 | *ptp = 0; |
1003 | ppc4xx_tlb_flush(va, pm->pm_ctx); | | 1003 | ppc4xx_tlb_flush(va, pm->pm_ctx); |
1004 | pm->pm_stats.resident_count--; | | 1004 | pm->pm_stats.resident_count--; |
1005 | } | | 1005 | } |
1006 | va += PAGE_SIZE; | | 1006 | va += PAGE_SIZE; |
1007 | } | | 1007 | } |
1008 | | | 1008 | |
1009 | splx(s); | | 1009 | splx(s); |
1010 | } | | 1010 | } |
1011 | | | 1011 | |
1012 | /* | | 1012 | /* |
1013 | * Get the physical page address for the given pmap/virtual address. | | 1013 | * Get the physical page address for the given pmap/virtual address. |
1014 | */ | | 1014 | */ |
1015 | bool | | 1015 | bool |
1016 | pmap_extract(struct pmap *pm, vaddr_t va, paddr_t *pap) | | 1016 | pmap_extract(struct pmap *pm, vaddr_t va, paddr_t *pap) |
1017 | { | | 1017 | { |
1018 | int seg = STIDX(va); | | 1018 | int seg = STIDX(va); |
1019 | int ptn = PTIDX(va); | | 1019 | int ptn = PTIDX(va); |
1020 | u_int pa = 0; | | 1020 | u_int pa = 0; |
1021 | int s; | | 1021 | int s; |
1022 | | | 1022 | |
1023 | s = splvm(); | | 1023 | s = splvm(); |
1024 | if (pm->pm_ptbl[seg] && (pa = pm->pm_ptbl[seg][ptn]) && pap) { | | 1024 | if (pm->pm_ptbl[seg] && (pa = pm->pm_ptbl[seg][ptn]) && pap) { |
1025 | *pap = TTE_PA(pa) | (va & PGOFSET); | | 1025 | *pap = TTE_PA(pa) | (va & PGOFSET); |
1026 | } | | 1026 | } |
1027 | splx(s); | | 1027 | splx(s); |
1028 | return (pa != 0); | | 1028 | return (pa != 0); |
1029 | } | | 1029 | } |
1030 | | | 1030 | |
1031 | /* | | 1031 | /* |
1032 | * Lower the protection on the specified range of this pmap. | | 1032 | * Lower the protection on the specified range of this pmap. |
1033 | * | | 1033 | * |
1034 | * There are only two cases: either the protection is going to 0, | | 1034 | * There are only two cases: either the protection is going to 0, |
1035 | * or it is going to read-only. | | 1035 | * or it is going to read-only. |
1036 | */ | | 1036 | */ |
1037 | void | | 1037 | void |
1038 | pmap_protect(struct pmap *pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot) | | 1038 | pmap_protect(struct pmap *pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot) |
1039 | { | | 1039 | { |
1040 | volatile u_int *ptp; | | 1040 | volatile u_int *ptp; |
1041 | int s, bic; | | 1041 | int s, bic; |
1042 | | | 1042 | |
1043 | if ((prot & VM_PROT_READ) == 0) { | | 1043 | if ((prot & VM_PROT_READ) == 0) { |
1044 | pmap_remove(pm, sva, eva); | | 1044 | pmap_remove(pm, sva, eva); |
1045 | return; | | 1045 | return; |
1046 | } | | 1046 | } |
1047 | bic = 0; | | 1047 | bic = 0; |
1048 | if ((prot & VM_PROT_WRITE) == 0) { | | 1048 | if ((prot & VM_PROT_WRITE) == 0) { |
1049 | bic |= TTE_WR; | | 1049 | bic |= TTE_WR; |
1050 | } | | 1050 | } |
1051 | if ((prot & VM_PROT_EXECUTE) == 0) { | | 1051 | if ((prot & VM_PROT_EXECUTE) == 0) { |
1052 | bic |= TTE_EX; | | 1052 | bic |= TTE_EX; |
1053 | } | | 1053 | } |
1054 | if (bic == 0) { | | 1054 | if (bic == 0) { |
1055 | return; | | 1055 | return; |
1056 | } | | 1056 | } |
1057 | s = splvm(); | | 1057 | s = splvm(); |
1058 | while (sva < eva) { | | 1058 | while (sva < eva) { |
1059 | if ((ptp = pte_find(pm, sva)) != NULL) { | | 1059 | if ((ptp = pte_find(pm, sva)) != NULL) { |
1060 | *ptp &= ~bic; | | 1060 | *ptp &= ~bic; |
1061 | ppc4xx_tlb_flush(sva, pm->pm_ctx); | | 1061 | ppc4xx_tlb_flush(sva, pm->pm_ctx); |
1062 | } | | 1062 | } |
1063 | sva += PAGE_SIZE; | | 1063 | sva += PAGE_SIZE; |
1064 | } | | 1064 | } |
1065 | splx(s); | | 1065 | splx(s); |
1066 | } | | 1066 | } |
1067 | | | 1067 | |
1068 | bool | | 1068 | bool |
1069 | pmap_check_attr(struct vm_page *pg, u_int mask, int clear) | | 1069 | pmap_check_attr(struct vm_page *pg, u_int mask, int clear) |
1070 | { | | 1070 | { |
1071 | paddr_t pa; | | 1071 | paddr_t pa; |
1072 | char *attr; | | 1072 | char *attr; |
1073 | int s, rv; | | 1073 | int s, rv; |
1074 | | | 1074 | |
1075 | /* | | 1075 | /* |
1076 | * First modify bits in cache. | | 1076 | * First modify bits in cache. |
1077 | */ | | 1077 | */ |
1078 | pa = VM_PAGE_TO_PHYS(pg); | | 1078 | pa = VM_PAGE_TO_PHYS(pg); |
1079 | attr = pa_to_attr(pa); | | 1079 | attr = pa_to_attr(pa); |
1080 | if (attr == NULL) | | 1080 | if (attr == NULL) |
1081 | return false; | | 1081 | return false; |
1082 | | | 1082 | |
1083 | s = splvm(); | | 1083 | s = splvm(); |
1084 | rv = ((*attr & mask) != 0); | | 1084 | rv = ((*attr & mask) != 0); |
1085 | if (clear) { | | 1085 | if (clear) { |
1086 | *attr &= ~mask; | | 1086 | *attr &= ~mask; |
1087 | pmap_page_protect(pg, mask == PMAP_ATTR_CHG ? VM_PROT_READ : 0); | | 1087 | pmap_page_protect(pg, mask == PMAP_ATTR_CHG ? VM_PROT_READ : 0); |
1088 | } | | 1088 | } |
1089 | splx(s); | | 1089 | splx(s); |
1090 | return rv; | | 1090 | return rv; |
1091 | } | | 1091 | } |
1092 | | | 1092 | |
1093 | | | 1093 | |
1094 | /* | | 1094 | /* |
1095 | * Lower the protection on the specified physical page. | | 1095 | * Lower the protection on the specified physical page. |
1096 | * | | 1096 | * |
1097 | * There are only two cases: either the protection is going to 0, | | 1097 | * There are only two cases: either the protection is going to 0, |
1098 | * or it is going to read-only. | | 1098 | * or it is going to read-only. |
1099 | */ | | 1099 | */ |
1100 | void | | 1100 | void |
1101 | pmap_page_protect(struct vm_page *pg, vm_prot_t prot) | | 1101 | pmap_page_protect(struct vm_page *pg, vm_prot_t prot) |
1102 | { | | 1102 | { |
1103 | paddr_t pa = VM_PAGE_TO_PHYS(pg); | | 1103 | paddr_t pa = VM_PAGE_TO_PHYS(pg); |
1104 | vaddr_t va; | | 1104 | vaddr_t va; |
1105 | struct pv_entry *pvh, *pv, *npv; | | 1105 | struct pv_entry *pvh, *pv, *npv; |
1106 | struct pmap *pm; | | 1106 | struct pmap *pm; |
1107 | | | 1107 | |
1108 | pvh = pa_to_pv(pa); | | 1108 | pvh = pa_to_pv(pa); |
1109 | if (pvh == NULL) | | 1109 | if (pvh == NULL) |
1110 | return; | | 1110 | return; |
1111 | | | 1111 | |
1112 | /* Handle extra pvs which may be deleted in the operation */ | | 1112 | /* Handle extra pvs which may be deleted in the operation */ |
1113 | for (pv = pvh->pv_next; pv; pv = npv) { | | 1113 | for (pv = pvh->pv_next; pv; pv = npv) { |
1114 | npv = pv->pv_next; | | 1114 | npv = pv->pv_next; |
1115 | | | 1115 | |
1116 | pm = pv->pv_pm; | | 1116 | pm = pv->pv_pm; |
1117 | va = pv->pv_va; | | 1117 | va = pv->pv_va; |
1118 | pmap_protect(pm, va, va + PAGE_SIZE, prot); | | 1118 | pmap_protect(pm, va, va + PAGE_SIZE, prot); |
1119 | } | | 1119 | } |
1120 | /* Now check the head pv */ | | 1120 | /* Now check the head pv */ |
1121 | if (pvh->pv_pm) { | | 1121 | if (pvh->pv_pm) { |
1122 | pv = pvh; | | 1122 | pv = pvh; |
1123 | pm = pv->pv_pm; | | 1123 | pm = pv->pv_pm; |
1124 | va = pv->pv_va; | | 1124 | va = pv->pv_va; |
1125 | pmap_protect(pm, va, va + PAGE_SIZE, prot); | | 1125 | pmap_protect(pm, va, va + PAGE_SIZE, prot); |
1126 | } | | 1126 | } |
1127 | } | | 1127 | } |
1128 | | | 1128 | |
1129 | /* | | 1129 | /* |
1130 | * Activate the address space for the specified process. If the process | | 1130 | * Activate the address space for the specified process. If the process |
1131 | * is the current process, load the new MMU context. | | 1131 | * is the current process, load the new MMU context. |
1132 | */ | | 1132 | */ |
1133 | void | | 1133 | void |
1134 | pmap_activate(struct lwp *l) | | 1134 | pmap_activate(struct lwp *l) |
1135 | { | | 1135 | { |
1136 | #if 0 | | 1136 | #if 0 |
1137 | struct pcb *pcb = lwp_getpcb(l); | | 1137 | struct pcb *pcb = lwp_getpcb(l); |
1138 | pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; | | 1138 | pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; |
1139 | | | 1139 | |
1140 | /* | | 1140 | /* |
1141 | * XXX Normally performed in cpu_lwp_fork(). | | 1141 | * XXX Normally performed in cpu_lwp_fork(). |
1142 | */ | | 1142 | */ |
1143 | printf("pmap_activate(%p), pmap=%p\n",l,pmap); | | 1143 | printf("pmap_activate(%p), pmap=%p\n",l,pmap); |
1144 | pcb->pcb_pm = pmap; | | 1144 | pcb->pcb_pm = pmap; |
1145 | #endif | | 1145 | #endif |
1146 | } | | 1146 | } |
1147 | | | 1147 | |
1148 | /* | | 1148 | /* |
1149 | * Deactivate the specified process's address space. | | 1149 | * Deactivate the specified process's address space. |
1150 | */ | | 1150 | */ |
1151 | void | | 1151 | void |
1152 | pmap_deactivate(struct lwp *l) | | 1152 | pmap_deactivate(struct lwp *l) |
1153 | { | | 1153 | { |
1154 | } | | 1154 | } |
1155 | | | 1155 | |
1156 | /* | | 1156 | /* |
1157 | * Synchronize caches corresponding to [addr, addr+len) in p. | | 1157 | * Synchronize caches corresponding to [addr, addr+len) in p. |
1158 | */ | | 1158 | */ |
1159 | void | | 1159 | void |
1160 | pmap_procwr(struct proc *p, vaddr_t va, size_t len) | | 1160 | pmap_procwr(struct proc *p, vaddr_t va, size_t len) |
1161 | { | | 1161 | { |
1162 | struct pmap *pm = p->p_vmspace->vm_map.pmap; | | 1162 | struct pmap *pm = p->p_vmspace->vm_map.pmap; |
1163 | int msr, ctx, opid, step; | | 1163 | int msr, ctx, opid, step; |
1164 | | | 1164 | |
1165 | step = CACHELINESIZE; | | 1165 | step = CACHELINESIZE; |
1166 | | | 1166 | |
1167 | /* | | 1167 | /* |
1168 | * Need to turn off IMMU and switch to user context. | | 1168 | * Need to turn off IMMU and switch to user context. |
1169 | * (icbi uses DMMU). | | 1169 | * (icbi uses DMMU). |
1170 | */ | | 1170 | */ |
1171 | if (!(ctx = pm->pm_ctx)) { | | 1171 | if (!(ctx = pm->pm_ctx)) { |
1172 | /* No context -- assign it one */ | | 1172 | /* No context -- assign it one */ |
1173 | ctx_alloc(pm); | | 1173 | ctx_alloc(pm); |
1174 | ctx = pm->pm_ctx; | | 1174 | ctx = pm->pm_ctx; |
1175 | } | | 1175 | } |
1176 | __asm volatile( | | 1176 | __asm volatile( |
1177 | "mfmsr %0;" | | 1177 | "mfmsr %0;" |
1178 | "li %1, %7;" | | 1178 | "li %1, %7;" |
1179 | "andc %1,%0,%1;" | | 1179 | "andc %1,%0,%1;" |
1180 | "mtmsr %1;" | | 1180 | "mtmsr %1;" |
1181 | "sync;isync;" | | 1181 | "sync;isync;" |
1182 | "mfpid %1;" | | 1182 | "mfpid %1;" |
1183 | "mtpid %2;" | | 1183 | "mtpid %2;" |
1184 | "sync; isync;" | | 1184 | "sync; isync;" |
1185 | "1:" | | 1185 | "1:" |
1186 | "dcbst 0,%3;" | | 1186 | "dcbst 0,%3;" |
1187 | "icbi 0,%3;" | | 1187 | "icbi 0,%3;" |
1188 | "add %3,%3,%5;" | | 1188 | "add %3,%3,%5;" |
1189 | "addc. %4,%4,%6;" | | 1189 | "addc. %4,%4,%6;" |
1190 | "bge 1b;" | | 1190 | "bge 1b;" |
1191 | "mtpid %1;" | | 1191 | "mtpid %1;" |
1192 | "mtmsr %0;" | | 1192 | "mtmsr %0;" |
1193 | "sync; isync" | | 1193 | "sync; isync" |
1194 | : "=&r" (msr), "=&r" (opid) | | 1194 | : "=&r" (msr), "=&r" (opid) |
1195 | : "r" (ctx), "r" (va), "r" (len), "r" (step), "r" (-step), | | 1195 | : "r" (ctx), "r" (va), "r" (len), "r" (step), "r" (-step), |
1196 | "K" (PSL_IR | PSL_DR)); | | 1196 | "K" (PSL_IR | PSL_DR)); |
1197 | } | | 1197 | } |
1198 | | | 1198 | |
1199 | | | 1199 | |
1200 | /* This has to be done in real mode !!! */ | | 1200 | /* This has to be done in real mode !!! */ |
1201 | void | | 1201 | void |
1202 | ppc4xx_tlb_flush(vaddr_t va, int pid) | | 1202 | ppc4xx_tlb_flush(vaddr_t va, int pid) |
1203 | { | | 1203 | { |
1204 | u_long i, found; | | 1204 | u_long i, found; |
1205 | u_long msr; | | 1205 | u_long msr; |
1206 | | | 1206 | |
1207 | /* If there's no context then it can't be mapped. */ | | 1207 | /* If there's no context then it can't be mapped. */ |
1208 | if (!pid) | | 1208 | if (!pid) |
1209 | return; | | 1209 | return; |
1210 | | | 1210 | |
1211 | __asm volatile( | | 1211 | __asm volatile( |
1212 | "mfpid %1;" /* Save PID */ | | 1212 | "mfpid %1;" /* Save PID */ |
1213 | "mfmsr %2;" /* Save MSR */ | | 1213 | "mfmsr %2;" /* Save MSR */ |
1214 | "li %0,0;" /* Now clear MSR */ | | 1214 | "li %0,0;" /* Now clear MSR */ |
1215 | "mtmsr %0;" | | 1215 | "mtmsr %0;" |
1216 | "mtpid %4;" /* Set PID */ | | 1216 | "mtpid %4;" /* Set PID */ |
1217 | "sync;" | | 1217 | "sync;" |
1218 | "tlbsx. %0,0,%3;" /* Search TLB */ | | 1218 | "tlbsx. %0,0,%3;" /* Search TLB */ |
1219 | "sync;" | | 1219 | "sync;" |
1220 | "mtpid %1;" /* Restore PID */ | | 1220 | "mtpid %1;" /* Restore PID */ |
1221 | "mtmsr %2;" /* Restore MSR */ | | 1221 | "mtmsr %2;" /* Restore MSR */ |
1222 | "sync;isync;" | | 1222 | "sync;isync;" |
1223 | "li %1,1;" | | 1223 | "li %1,1;" |
1224 | "beq 1f;" | | 1224 | "beq 1f;" |
1225 | "li %1,0;" | | 1225 | "li %1,0;" |
1226 | "1:" | | 1226 | "1:" |
1227 | : "=&r" (i), "=&r" (found), "=&r" (msr) | | 1227 | : "=&r" (i), "=&r" (found), "=&r" (msr) |
1228 | : "r" (va), "r" (pid)); | | 1228 | : "r" (va), "r" (pid)); |
1229 | if (found && !TLB_LOCKED(i)) { | | 1229 | if (found && !TLB_LOCKED(i)) { |
1230 | /* Now flush translation */ | | 1230 | /* Now flush translation */ |
1231 | __asm volatile( | | 1231 | __asm volatile( |
1232 | "tlbwe %0,%1,0;" | | 1232 | "tlbwe %0,%1,0;" |
1233 | "sync;isync;" | | 1233 | "sync;isync;" |
1234 | : : "r" (0), "r" (i)); | | 1234 | : : "r" (0), "r" (i)); |
1235 | | | 1235 | |
1236 | tlb_info[i].ti_ctx = 0; | | 1236 | tlb_info[i].ti_ctx = 0; |
1237 | tlb_info[i].ti_flags = 0; | | 1237 | tlb_info[i].ti_flags = 0; |
1238 | tlbnext = i; | | 1238 | tlbnext = i; |
1239 | /* Successful flushes */ | | 1239 | /* Successful flushes */ |
1240 | tlbflush_ev.ev_count++; | | 1240 | tlbflush_ev.ev_count++; |
1241 | } | | 1241 | } |
1242 | } | | 1242 | } |
1243 | | | 1243 | |
1244 | void | | 1244 | void |
1245 | ppc4xx_tlb_flush_all(void) | | 1245 | ppc4xx_tlb_flush_all(void) |
1246 | { | | 1246 | { |
1247 | u_long i; | | 1247 | u_long i; |
1248 | | | 1248 | |
1249 | for (i = 0; i < NTLB; i++) | | 1249 | for (i = 0; i < NTLB; i++) |
1250 | if (!TLB_LOCKED(i)) { | | 1250 | if (!TLB_LOCKED(i)) { |
1251 | __asm volatile( | | 1251 | __asm volatile( |
1252 | "tlbwe %0,%1,0;" | | 1252 | "tlbwe %0,%1,0;" |
1253 | "sync;isync;" | | 1253 | "sync;isync;" |
1254 | : : "r" (0), "r" (i)); | | 1254 | : : "r" (0), "r" (i)); |
1255 | tlb_info[i].ti_ctx = 0; | | 1255 | tlb_info[i].ti_ctx = 0; |
1256 | tlb_info[i].ti_flags = 0; | | 1256 | tlb_info[i].ti_flags = 0; |
1257 | } | | 1257 | } |
1258 | | | 1258 | |
1259 | __asm volatile("sync;isync"); | | 1259 | __asm volatile("sync;isync"); |
1260 | } | | 1260 | } |
1261 | | | 1261 | |
1262 | /* Find a TLB entry to evict. */ | | 1262 | /* Find a TLB entry to evict. */ |
1263 | static int | | 1263 | static int |
1264 | ppc4xx_tlb_find_victim(void) | | 1264 | ppc4xx_tlb_find_victim(void) |
1265 | { | | 1265 | { |
1266 | int flags; | | 1266 | int flags; |
1267 | | | 1267 | |
1268 | for (;;) { | | 1268 | for (;;) { |
1269 | if (++tlbnext >= NTLB) | | 1269 | if (++tlbnext >= NTLB) |
1270 | tlbnext = tlb_nreserved; | | 1270 | tlbnext = tlb_nreserved; |
1271 | flags = tlb_info[tlbnext].ti_flags; | | 1271 | flags = tlb_info[tlbnext].ti_flags; |
1272 | if (!(flags & TLBF_USED) || | | 1272 | if (!(flags & TLBF_USED) || |
1273 | (flags & (TLBF_LOCKED | TLBF_REF)) == 0) { | | 1273 | (flags & (TLBF_LOCKED | TLBF_REF)) == 0) { |
1274 | u_long va, stack = (u_long)&va; | | 1274 | u_long va, stack = (u_long)&va; |
1275 | | | 1275 | |
1276 | if (!((tlb_info[tlbnext].ti_va ^ stack) & (~PGOFSET)) && | | 1276 | if (!((tlb_info[tlbnext].ti_va ^ stack) & (~PGOFSET)) && |
1277 | (tlb_info[tlbnext].ti_ctx == KERNEL_PID) && | | 1277 | (tlb_info[tlbnext].ti_ctx == KERNEL_PID) && |
1278 | (flags & TLBF_USED)) { | | 1278 | (flags & TLBF_USED)) { |
1279 | /* Kernel stack page */ | | 1279 | /* Kernel stack page */ |
1280 | flags |= TLBF_REF; | | 1280 | flags |= TLBF_REF; |
1281 | tlb_info[tlbnext].ti_flags = flags; | | 1281 | tlb_info[tlbnext].ti_flags = flags; |
1282 | } else { | | 1282 | } else { |
1283 | /* Found it! */ | | 1283 | /* Found it! */ |
1284 | return (tlbnext); | | 1284 | return (tlbnext); |
1285 | } | | 1285 | } |
1286 | } else { | | 1286 | } else { |
1287 | tlb_info[tlbnext].ti_flags = (flags & ~TLBF_REF); | | 1287 | tlb_info[tlbnext].ti_flags = (flags & ~TLBF_REF); |
1288 | } | | 1288 | } |
1289 | } | | 1289 | } |
1290 | } | | 1290 | } |
1291 | | | 1291 | |
1292 | void | | 1292 | void |
1293 | ppc4xx_tlb_enter(int ctx, vaddr_t va, u_int pte) | | 1293 | ppc4xx_tlb_enter(int ctx, vaddr_t va, u_int pte) |
1294 | { | | 1294 | { |
1295 | u_long th, tl, idx; | | 1295 | u_long th, tl, idx; |
1296 | tlbpid_t pid; | | 1296 | int msr, pid; |
1297 | u_short msr; | | | |
1298 | paddr_t pa; | | 1297 | paddr_t pa; |
1299 | int sz; | | 1298 | int sz; |
1300 | | | 1299 | |
1301 | tlbenter_ev.ev_count++; | | 1300 | tlbenter_ev.ev_count++; |
1302 | | | 1301 | |
1303 | sz = (pte & TTE_SZ_MASK) >> TTE_SZ_SHIFT; | | 1302 | sz = (pte & TTE_SZ_MASK) >> TTE_SZ_SHIFT; |
1304 | pa = (pte & TTE_RPN_MASK(sz)); | | 1303 | pa = (pte & TTE_RPN_MASK(sz)); |
1305 | th = (va & TLB_EPN_MASK) | (sz << TLB_SIZE_SHFT) | TLB_VALID; | | 1304 | th = (va & TLB_EPN_MASK) | (sz << TLB_SIZE_SHFT) | TLB_VALID; |
1306 | tl = (pte & ~TLB_RPN_MASK) | pa; | | 1305 | tl = (pte & ~TLB_RPN_MASK) | pa; |
1307 | tl |= ppc4xx_tlbflags(va, pa); | | 1306 | tl |= ppc4xx_tlbflags(va, pa); |
1308 | | | 1307 | |
1309 | idx = ppc4xx_tlb_find_victim(); | | 1308 | idx = ppc4xx_tlb_find_victim(); |
1310 | | | 1309 | |
1311 | #ifdef DIAGNOSTIC | | 1310 | #ifdef DIAGNOSTIC |
1312 | if ((idx < tlb_nreserved) || (idx >= NTLB) || (idx & 63) == 0) { | | 1311 | if ((idx < tlb_nreserved) || (idx >= NTLB) || (idx & 63) == 0) { |
1313 | panic("ppc4xx_tlb_enter: replacing entry %ld", idx); | | 1312 | panic("ppc4xx_tlb_enter: replacing entry %ld", idx); |
1314 | } | | 1313 | } |
1315 | #endif | | 1314 | #endif |
1316 | | | 1315 | |
1317 | tlb_info[idx].ti_va = (va & TLB_EPN_MASK); | | 1316 | tlb_info[idx].ti_va = (va & TLB_EPN_MASK); |
1318 | tlb_info[idx].ti_ctx = ctx; | | 1317 | tlb_info[idx].ti_ctx = ctx; |
1319 | tlb_info[idx].ti_flags = TLBF_USED | TLBF_REF; | | 1318 | tlb_info[idx].ti_flags = TLBF_USED | TLBF_REF; |
1320 | | | 1319 | |
1321 | __asm volatile( | | 1320 | __asm volatile( |
1322 | "mfmsr %0;" /* Save MSR */ | | 1321 | "mfmsr %0;" /* Save MSR */ |
1323 | "li %1,0;" | | 1322 | "li %1,0;" |
1324 | "mtmsr %1;" /* Clear MSR */ | | 1323 | "mtmsr %1;" /* Clear MSR */ |
1325 | "tlbwe %1,%3,0;" /* Invalidate old entry. */ | | 1324 | "tlbwe %1,%3,0;" /* Invalidate old entry. */ |
1326 | "mfpid %1;" /* Save old PID */ | | 1325 | "mfpid %1;" /* Save old PID */ |
1327 | "mtpid %2;" /* Load translation ctx */ | | 1326 | "mtpid %2;" /* Load translation ctx */ |
1328 | "sync; isync;" | | 1327 | "sync; isync;" |
1329 | "tlbwe %4,%3,1; tlbwe %5,%3,0;" /* Set TLB */ | | 1328 | "tlbwe %4,%3,1; tlbwe %5,%3,0;" /* Set TLB */ |
1330 | "sync; isync;" | | 1329 | "sync; isync;" |
1331 | "mtpid %1; mtmsr %0;" /* Restore PID and MSR */ | | 1330 | "mtpid %1; mtmsr %0;" /* Restore PID and MSR */ |
1332 | "sync; isync;" | | 1331 | "sync; isync;" |
1333 | : "=&r" (msr), "=&r" (pid) | | 1332 | : "=&r" (msr), "=&r" (pid) |
1334 | : "r" (ctx), "r" (idx), "r" (tl), "r" (th)); | | 1333 | : "r" (ctx), "r" (idx), "r" (tl), "r" (th)); |
1335 | } | | 1334 | } |
1336 | | | 1335 | |
1337 | void | | 1336 | void |
1338 | ppc4xx_tlb_init(void) | | 1337 | ppc4xx_tlb_init(void) |
1339 | { | | 1338 | { |
1340 | int i; | | 1339 | int i; |
1341 | | | 1340 | |
1342 | /* Mark reserved TLB entries */ | | 1341 | /* Mark reserved TLB entries */ |
1343 | for (i = 0; i < tlb_nreserved; i++) { | | 1342 | for (i = 0; i < tlb_nreserved; i++) { |
1344 | tlb_info[i].ti_flags = TLBF_LOCKED | TLBF_USED; | | 1343 | tlb_info[i].ti_flags = TLBF_LOCKED | TLBF_USED; |
1345 | tlb_info[i].ti_ctx = KERNEL_PID; | | 1344 | tlb_info[i].ti_ctx = KERNEL_PID; |
1346 | } | | 1345 | } |
1347 | | | 1346 | |
1348 | /* Setup security zones */ | | 1347 | /* Setup security zones */ |
1349 | /* Z0 - accessible by kernel only if TLB entry permissions allow | | 1348 | /* Z0 - accessible by kernel only if TLB entry permissions allow |
1350 | * Z1,Z2 - access is controlled by TLB entry permissions | | 1349 | * Z1,Z2 - access is controlled by TLB entry permissions |
1351 | * Z3 - full access regardless of TLB entry permissions | | 1350 | * Z3 - full access regardless of TLB entry permissions |
1352 | */ | | 1351 | */ |
1353 | | | 1352 | |
1354 | __asm volatile( | | 1353 | __asm volatile( |
1355 | "mtspr %0,%1;" | | 1354 | "mtspr %0,%1;" |
1356 | "sync;" | | 1355 | "sync;" |
1357 | :: "K"(SPR_ZPR), "r" (0x1b000000)); | | 1356 | :: "K"(SPR_ZPR), "r" (0x1b000000)); |
1358 | } | | 1357 | } |
1359 | | | 1358 | |
1360 | /* | | 1359 | /* |
1361 | * ppc4xx_tlb_size_mask: | | 1360 | * ppc4xx_tlb_size_mask: |
1362 | * | | 1361 | * |
1363 | * Roundup size to supported page size, return TLBHI mask and real size. | | 1362 | * Roundup size to supported page size, return TLBHI mask and real size. |
1364 | */ | | 1363 | */ |
1365 | static int | | 1364 | static int |
1366 | ppc4xx_tlb_size_mask(size_t size, int *mask, int *rsiz) | | 1365 | ppc4xx_tlb_size_mask(size_t size, int *mask, int *rsiz) |
1367 | { | | 1366 | { |
1368 | int i; | | 1367 | int i; |
1369 | | | 1368 | |
1370 | for (i = 0; i < __arraycount(tlbsize); i++) | | 1369 | for (i = 0; i < __arraycount(tlbsize); i++) |
1371 | if (size <= tlbsize[i]) { | | 1370 | if (size <= tlbsize[i]) { |
1372 | *mask = (i << TLB_SIZE_SHFT); | | 1371 | *mask = (i << TLB_SIZE_SHFT); |
1373 | *rsiz = tlbsize[i]; | | 1372 | *rsiz = tlbsize[i]; |
1374 | return (0); | | 1373 | return (0); |
1375 | } | | 1374 | } |
1376 | return (EINVAL); | | 1375 | return (EINVAL); |
1377 | } | | 1376 | } |
1378 | | | 1377 | |
1379 | /* | | 1378 | /* |
1380 | * ppc4xx_tlb_mapiodev: | | 1379 | * ppc4xx_tlb_mapiodev: |
1381 | * | | 1380 | * |
1382 | * Lookup virtual address of mapping previously entered via | | 1381 | * Lookup virtual address of mapping previously entered via |
1383 | * ppc4xx_tlb_reserve. Search TLB directly so that we don't | | 1382 | * ppc4xx_tlb_reserve. Search TLB directly so that we don't |
1384 | * need to waste extra storage for reserved mappings. Note | | 1383 | * need to waste extra storage for reserved mappings. Note |
1385 | * that reading TLBHI also sets PID, but all reserved mappings | | 1384 | * that reading TLBHI also sets PID, but all reserved mappings |
1386 | * use KERNEL_PID, so the side effect is nil. | | 1385 | * use KERNEL_PID, so the side effect is nil. |
1387 | */ | | 1386 | */ |
1388 | void * | | 1387 | void * |
1389 | ppc4xx_tlb_mapiodev(paddr_t base, psize_t len) | | 1388 | ppc4xx_tlb_mapiodev(paddr_t base, psize_t len) |
1390 | { | | 1389 | { |
1391 | paddr_t pa; | | 1390 | paddr_t pa; |
1392 | vaddr_t va; | | 1391 | vaddr_t va; |
1393 | u_int lo, hi, sz; | | 1392 | u_int lo, hi, sz; |
1394 | int i; | | 1393 | int i; |
1395 | | | 1394 | |
1396 | /* tlb_nreserved is only allowed to grow, so this is safe. */ | | 1395 | /* tlb_nreserved is only allowed to grow, so this is safe. */ |
1397 | for (i = 0; i < tlb_nreserved; i++) { | | 1396 | for (i = 0; i < tlb_nreserved; i++) { |
1398 | __asm volatile ( | | 1397 | __asm volatile ( |
1399 | " tlbre %0,%2,1 \n" /* TLBLO */ | | 1398 | " tlbre %0,%2,1 \n" /* TLBLO */ |
1400 | " tlbre %1,%2,0 \n" /* TLBHI */ | | 1399 | " tlbre %1,%2,0 \n" /* TLBHI */ |
1401 | : "=&r" (lo), "=&r" (hi) | | 1400 | : "=&r" (lo), "=&r" (hi) |
1402 | : "r" (i)); | | 1401 | : "r" (i)); |
1403 | | | 1402 | |
1404 | KASSERT(hi & TLB_VALID); | | 1403 | KASSERT(hi & TLB_VALID); |
1405 | KASSERT(mfspr(SPR_PID) == KERNEL_PID); | | 1404 | KASSERT(mfspr(SPR_PID) == KERNEL_PID); |
1406 | | | 1405 | |
1407 | pa = (lo & TLB_RPN_MASK); | | 1406 | pa = (lo & TLB_RPN_MASK); |
1408 | if (base < pa) | | 1407 | if (base < pa) |
1409 | continue; | | 1408 | continue; |
1410 | | | 1409 | |
1411 | sz = tlbsize[(hi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT]; | | 1410 | sz = tlbsize[(hi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT]; |
1412 | if ((base + len) > (pa + sz)) | | 1411 | if ((base + len) > (pa + sz)) |
1413 | continue; | | 1412 | continue; |
1414 | | | 1413 | |
1415 | va = (hi & TLB_EPN_MASK) + (base & (sz - 1)); /* sz = 2^n */ | | 1414 | va = (hi & TLB_EPN_MASK) + (base & (sz - 1)); /* sz = 2^n */ |
1416 | return (void *)(va); | | 1415 | return (void *)(va); |
1417 | } | | 1416 | } |
1418 | | | 1417 | |
1419 | return (NULL); | | 1418 | return (NULL); |
1420 | } | | 1419 | } |
1421 | | | 1420 | |
1422 | /* | | 1421 | /* |
1423 | * ppc4xx_tlb_reserve: | | 1422 | * ppc4xx_tlb_reserve: |
1424 | * | | 1423 | * |
1425 | * Map physical range to kernel virtual chunk via reserved TLB entry. | | 1424 | * Map physical range to kernel virtual chunk via reserved TLB entry. |
1426 | */ | | 1425 | */ |
1427 | void | | 1426 | void |
1428 | ppc4xx_tlb_reserve(paddr_t pa, vaddr_t va, size_t size, int flags) | | 1427 | ppc4xx_tlb_reserve(paddr_t pa, vaddr_t va, size_t size, int flags) |
1429 | { | | 1428 | { |
1430 | u_int lo, hi; | | 1429 | u_int lo, hi; |
1431 | int szmask, rsize; | | 1430 | int szmask, rsize; |
1432 | | | 1431 | |
1433 | /* Called before pmap_bootstrap(), va outside kernel space. */ | | 1432 | /* Called before pmap_bootstrap(), va outside kernel space. */ |
1434 | KASSERT(va < VM_MIN_KERNEL_ADDRESS || va >= VM_MAX_KERNEL_ADDRESS); | | 1433 | KASSERT(va < VM_MIN_KERNEL_ADDRESS || va >= VM_MAX_KERNEL_ADDRESS); |
1435 | KASSERT(! pmap_bootstrap_done); | | 1434 | KASSERT(! pmap_bootstrap_done); |
1436 | KASSERT(tlb_nreserved < NTLB); | | 1435 | KASSERT(tlb_nreserved < NTLB); |
1437 | | | 1436 | |
1438 | /* Resolve size. */ | | 1437 | /* Resolve size. */ |
1439 | if (ppc4xx_tlb_size_mask(size, &szmask, &rsize) != 0) | | 1438 | if (ppc4xx_tlb_size_mask(size, &szmask, &rsize) != 0) |
1440 | panic("ppc4xx_tlb_reserve: entry %d, %zuB too large", | | 1439 | panic("ppc4xx_tlb_reserve: entry %d, %zuB too large", |
1441 | size, tlb_nreserved); | | 1440 | size, tlb_nreserved); |
1442 | | | 1441 | |
1443 | /* Real size will be power of two >= 1024, so this is OK. */ | | 1442 | /* Real size will be power of two >= 1024, so this is OK. */ |
1444 | pa &= ~(rsize - 1); /* RPN */ | | 1443 | pa &= ~(rsize - 1); /* RPN */ |
1445 | va &= ~(rsize - 1); /* EPN */ | | 1444 | va &= ~(rsize - 1); /* EPN */ |
1446 | | | 1445 | |
1447 | lo = pa | TLB_WR | flags; | | 1446 | lo = pa | TLB_WR | flags; |
1448 | hi = va | TLB_VALID | szmask; | | 1447 | hi = va | TLB_VALID | szmask; |
1449 | | | 1448 | |
1450 | #ifdef PPC_4XX_NOCACHE | | 1449 | #ifdef PPC_4XX_NOCACHE |
1451 | lo |= TLB_I; | | 1450 | lo |= TLB_I; |
1452 | #endif | | 1451 | #endif |
1453 | | | 1452 | |
1454 | __asm volatile( | | 1453 | __asm volatile( |
1455 | " tlbwe %1,%0,1 \n" /* write TLBLO */ | | 1454 | " tlbwe %1,%0,1 \n" /* write TLBLO */ |
1456 | " tlbwe %2,%0,0 \n" /* write TLBHI */ | | 1455 | " tlbwe %2,%0,0 \n" /* write TLBHI */ |
1457 | " sync \n" | | 1456 | " sync \n" |
1458 | " isync \n" | | 1457 | " isync \n" |
1459 | : : "r" (tlb_nreserved), "r" (lo), "r" (hi)); | | 1458 | : : "r" (tlb_nreserved), "r" (lo), "r" (hi)); |
1460 | | | 1459 | |
1461 | tlb_nreserved++; | | 1460 | tlb_nreserved++; |
1462 | } | | 1461 | } |
1463 | | | 1462 | |
1464 | /* | | 1463 | /* |
1465 | * We should pass the ctx in from trap code. | | 1464 | * We should pass the ctx in from trap code. |
1466 | */ | | 1465 | */ |
1467 | int | | 1466 | int |
1468 | pmap_tlbmiss(vaddr_t va, int ctx) | | 1467 | pmap_tlbmiss(vaddr_t va, int ctx) |
1469 | { | | 1468 | { |
1470 | volatile u_int *pte; | | 1469 | volatile u_int *pte; |
1471 | u_long tte; | | 1470 | u_long tte; |
1472 | | | 1471 | |
1473 | tlbmiss_ev.ev_count++; | | 1472 | tlbmiss_ev.ev_count++; |
1474 | | | 1473 | |
1475 | /* | | 1474 | /* |
1476 | * We will reserve 0 upto VM_MIN_KERNEL_ADDRESS for va == pa mappings. | | 1475 | * We will reserve 0 upto VM_MIN_KERNEL_ADDRESS for va == pa mappings. |
1477 | * Physical RAM is expected to live in this range, care must be taken | | 1476 | * Physical RAM is expected to live in this range, care must be taken |
1478 | * to not clobber 0 upto ${physmem} with device mappings in machdep | | 1477 | * to not clobber 0 upto ${physmem} with device mappings in machdep |
1479 | * code. | | 1478 | * code. |
1480 | */ | | 1479 | */ |
1481 | if (ctx != KERNEL_PID || | | 1480 | if (ctx != KERNEL_PID || |
1482 | (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS)) { | | 1481 | (va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS)) { |
1483 | pte = pte_find((struct pmap *)__UNVOLATILE(ctxbusy[ctx]), va); | | 1482 | pte = pte_find((struct pmap *)__UNVOLATILE(ctxbusy[ctx]), va); |
1484 | if (pte == NULL) { | | 1483 | if (pte == NULL) { |
1485 | /* Map unmanaged addresses directly for kernel access */ | | 1484 | /* Map unmanaged addresses directly for kernel access */ |
1486 | return 1; | | 1485 | return 1; |
1487 | } | | 1486 | } |
1488 | tte = *pte; | | 1487 | tte = *pte; |
1489 | if (tte == 0) { | | 1488 | if (tte == 0) { |
1490 | return 1; | | 1489 | return 1; |
1491 | } | | 1490 | } |
1492 | } else { | | 1491 | } else { |
1493 | /* Create a 16MB writable mapping. */ | | 1492 | /* Create a 16MB writable mapping. */ |
1494 | #ifdef PPC_4XX_NOCACHE | | 1493 | #ifdef PPC_4XX_NOCACHE |
1495 | tte = TTE_PA(va) | TTE_ZONE(ZONE_PRIV) | TTE_SZ_16M | TTE_I |TTE_WR; | | 1494 | tte = TTE_PA(va) | TTE_ZONE(ZONE_PRIV) | TTE_SZ_16M | TTE_I |TTE_WR; |
1496 | #else | | 1495 | #else |
1497 | tte = TTE_PA(va) | TTE_ZONE(ZONE_PRIV) | TTE_SZ_16M | TTE_WR; | | 1496 | tte = TTE_PA(va) | TTE_ZONE(ZONE_PRIV) | TTE_SZ_16M | TTE_WR; |
1498 | #endif | | 1497 | #endif |
1499 | } | | 1498 | } |
1500 | tlbhit_ev.ev_count++; | | 1499 | tlbhit_ev.ev_count++; |
1501 | ppc4xx_tlb_enter(ctx, va, tte); | | 1500 | ppc4xx_tlb_enter(ctx, va, tte); |
1502 | | | 1501 | |
1503 | return 0; | | 1502 | return 0; |
1504 | } | | 1503 | } |
1505 | | | 1504 | |
1506 | /* | | 1505 | /* |
1507 | * Flush all the entries matching a context from the TLB. | | 1506 | * Flush all the entries matching a context from the TLB. |
1508 | */ | | 1507 | */ |
1509 | static int | | 1508 | static int |
1510 | ctx_flush(int cnum) | | 1509 | ctx_flush(int cnum) |
1511 | { | | 1510 | { |
1512 | int i; | | 1511 | int i; |
1513 | | | 1512 | |
1514 | /* We gotta steal this context */ | | 1513 | /* We gotta steal this context */ |
1515 | for (i = tlb_nreserved; i < NTLB; i++) { | | 1514 | for (i = tlb_nreserved; i < NTLB; i++) { |
1516 | if (tlb_info[i].ti_ctx == cnum) { | | 1515 | if (tlb_info[i].ti_ctx == cnum) { |
1517 | /* Can't steal ctx if it has a locked entry. */ | | 1516 | /* Can't steal ctx if it has a locked entry. */ |
1518 | if (TLB_LOCKED(i)) { | | 1517 | if (TLB_LOCKED(i)) { |
1519 | #ifdef DIAGNOSTIC | | 1518 | #ifdef DIAGNOSTIC |
1520 | printf("ctx_flush: can't invalidate " | | 1519 | printf("ctx_flush: can't invalidate " |
1521 | "locked mapping %d " | | 1520 | "locked mapping %d " |
1522 | "for context %d\n", i, cnum); | | 1521 | "for context %d\n", i, cnum); |
1523 | #ifdef DDB | | 1522 | #ifdef DDB |
1524 | Debugger(); | | 1523 | Debugger(); |
1525 | #endif | | 1524 | #endif |
1526 | #endif | | 1525 | #endif |
1527 | return (1); | | 1526 | return (1); |
1528 | } | | 1527 | } |
1529 | #ifdef DIAGNOSTIC | | 1528 | #ifdef DIAGNOSTIC |
1530 | if (i < tlb_nreserved) | | 1529 | if (i < tlb_nreserved) |
1531 | panic("TLB entry %d not locked", i); | | 1530 | panic("TLB entry %d not locked", i); |
1532 | #endif | | 1531 | #endif |
1533 | /* Invalidate particular TLB entry regardless of locked status */ | | 1532 | /* Invalidate particular TLB entry regardless of locked status */ |
1534 | __asm volatile("tlbwe %0,%1,0" : :"r"(0),"r"(i)); | | 1533 | __asm volatile("tlbwe %0,%1,0" : :"r"(0),"r"(i)); |
1535 | tlb_info[i].ti_ctx = 0; | | 1534 | tlb_info[i].ti_ctx = 0; |
1536 | tlb_info[i].ti_flags = 0; | | 1535 | tlb_info[i].ti_flags = 0; |
1537 | } | | 1536 | } |
1538 | } | | 1537 | } |
1539 | return (0); | | 1538 | return (0); |
1540 | } | | 1539 | } |
1541 | | | 1540 | |
1542 | /* | | 1541 | /* |
1543 | * Allocate a context. If necessary, steal one from someone else. | | 1542 | * Allocate a context. If necessary, steal one from someone else. |
1544 | * | | 1543 | * |
1545 | * The new context is flushed from the TLB before returning. | | 1544 | * The new context is flushed from the TLB before returning. |
1546 | */ | | 1545 | */ |
1547 | int | | 1546 | int |
1548 | ctx_alloc(struct pmap *pm) | | 1547 | ctx_alloc(struct pmap *pm) |
1549 | { | | 1548 | { |
1550 | int s, cnum; | | 1549 | int s, cnum; |
1551 | static int next = MINCTX; | | 1550 | static int next = MINCTX; |
1552 | | | 1551 | |
1553 | if (pm == pmap_kernel()) { | | 1552 | if (pm == pmap_kernel()) { |
1554 | #ifdef DIAGNOSTIC | | 1553 | #ifdef DIAGNOSTIC |
1555 | printf("ctx_alloc: kernel pmap!\n"); | | 1554 | printf("ctx_alloc: kernel pmap!\n"); |
1556 | #endif | | 1555 | #endif |
1557 | return (0); | | 1556 | return (0); |
1558 | } | | 1557 | } |
1559 | s = splvm(); | | 1558 | s = splvm(); |
1560 | | | 1559 | |
1561 | /* Find a likely context. */ | | 1560 | /* Find a likely context. */ |
1562 | cnum = next; | | 1561 | cnum = next; |
1563 | do { | | 1562 | do { |
1564 | if ((++cnum) >= NUMCTX) | | 1563 | if ((++cnum) >= NUMCTX) |
1565 | cnum = MINCTX; | | 1564 | cnum = MINCTX; |
1566 | } while (ctxbusy[cnum] != NULL && cnum != next); | | 1565 | } while (ctxbusy[cnum] != NULL && cnum != next); |
1567 | | | 1566 | |
1568 | /* Now clean it out */ | | 1567 | /* Now clean it out */ |
1569 | oops: | | 1568 | oops: |
1570 | if (cnum < MINCTX) | | 1569 | if (cnum < MINCTX) |
1571 | cnum = MINCTX; /* Never steal ctx 0 or 1 */ | | 1570 | cnum = MINCTX; /* Never steal ctx 0 or 1 */ |
1572 | if (ctx_flush(cnum)) { | | 1571 | if (ctx_flush(cnum)) { |
1573 | /* oops -- something's wired. */ | | 1572 | /* oops -- something's wired. */ |
1574 | if ((++cnum) >= NUMCTX) | | 1573 | if ((++cnum) >= NUMCTX) |
1575 | cnum = MINCTX; | | 1574 | cnum = MINCTX; |
1576 | goto oops; | | 1575 | goto oops; |
1577 | } | | 1576 | } |
1578 | | | 1577 | |
1579 | if (ctxbusy[cnum]) { | | 1578 | if (ctxbusy[cnum]) { |
1580 | #ifdef DEBUG | | 1579 | #ifdef DEBUG |
1581 | /* We should identify this pmap and clear it */ | | 1580 | /* We should identify this pmap and clear it */ |
1582 | printf("Warning: stealing context %d\n", cnum); | | 1581 | printf("Warning: stealing context %d\n", cnum); |
1583 | #endif | | 1582 | #endif |
1584 | ctxbusy[cnum]->pm_ctx = 0; | | 1583 | ctxbusy[cnum]->pm_ctx = 0; |
1585 | } | | 1584 | } |
1586 | ctxbusy[cnum] = pm; | | 1585 | ctxbusy[cnum] = pm; |
1587 | next = cnum; | | 1586 | next = cnum; |
1588 | splx(s); | | 1587 | splx(s); |
1589 | pm->pm_ctx = cnum; | | 1588 | pm->pm_ctx = cnum; |
1590 | | | 1589 | |
1591 | return cnum; | | 1590 | return cnum; |
1592 | } | | 1591 | } |
1593 | | | 1592 | |
1594 | /* | | 1593 | /* |
1595 | * Give away a context. | | 1594 | * Give away a context. |
1596 | */ | | 1595 | */ |
1597 | void | | 1596 | void |
1598 | ctx_free(struct pmap *pm) | | 1597 | ctx_free(struct pmap *pm) |
1599 | { | | 1598 | { |
1600 | int oldctx; | | 1599 | int oldctx; |
1601 | | | 1600 | |
1602 | oldctx = pm->pm_ctx; | | 1601 | oldctx = pm->pm_ctx; |
1603 | | | 1602 | |
1604 | if (oldctx == 0) | | 1603 | if (oldctx == 0) |
1605 | panic("ctx_free: freeing kernel context"); | | 1604 | panic("ctx_free: freeing kernel context"); |
1606 | #ifdef DIAGNOSTIC | | 1605 | #ifdef DIAGNOSTIC |
1607 | if (ctxbusy[oldctx] == 0) | | 1606 | if (ctxbusy[oldctx] == 0) |
1608 | printf("ctx_free: freeing free context %d\n", oldctx); | | 1607 | printf("ctx_free: freeing free context %d\n", oldctx); |
1609 | if (ctxbusy[oldctx] != pm) { | | 1608 | if (ctxbusy[oldctx] != pm) { |
1610 | printf("ctx_free: freeing someone esle's context\n " | | 1609 | printf("ctx_free: freeing someone esle's context\n " |
1611 | "ctxbusy[%d] = %p, pm->pm_ctx = %p\n", | | 1610 | "ctxbusy[%d] = %p, pm->pm_ctx = %p\n", |
1612 | oldctx, (void *)(u_long)ctxbusy[oldctx], pm); | | 1611 | oldctx, (void *)(u_long)ctxbusy[oldctx], pm); |
1613 | #ifdef DDB | | 1612 | #ifdef DDB |
1614 | Debugger(); | | 1613 | Debugger(); |
1615 | #endif | | 1614 | #endif |
1616 | } | | 1615 | } |
1617 | #endif | | 1616 | #endif |
1618 | /* We should verify it has not been stolen and reallocated... */ | | 1617 | /* We should verify it has not been stolen and reallocated... */ |
1619 | ctxbusy[oldctx] = NULL; | | 1618 | ctxbusy[oldctx] = NULL; |
1620 | ctx_flush(oldctx); | | 1619 | ctx_flush(oldctx); |
1621 | } | | 1620 | } |
1622 | | | 1621 | |
1623 | | | 1622 | |
1624 | #ifdef DEBUG | | 1623 | #ifdef DEBUG |
1625 | /* | | 1624 | /* |
1626 | * Test ref/modify handling. | | 1625 | * Test ref/modify handling. |
1627 | */ | | 1626 | */ |
1628 | void pmap_testout(void); | | 1627 | void pmap_testout(void); |
1629 | void | | 1628 | void |
1630 | pmap_testout(void) | | 1629 | pmap_testout(void) |
1631 | { | | 1630 | { |
1632 | vaddr_t va; | | 1631 | vaddr_t va; |
1633 | volatile int *loc; | | 1632 | volatile int *loc; |
1634 | int val = 0; | | 1633 | int val = 0; |
1635 | paddr_t pa; | | 1634 | paddr_t pa; |
1636 | struct vm_page *pg; | | 1635 | struct vm_page *pg; |
1637 | int ref, mod; | | 1636 | int ref, mod; |
1638 | | | 1637 | |
1639 | /* Allocate a page */ | | 1638 | /* Allocate a page */ |
1640 | va = (vaddr_t)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, | | 1639 | va = (vaddr_t)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
1641 | UVM_KMF_WIRED | UVM_KMF_ZERO); | | 1640 | UVM_KMF_WIRED | UVM_KMF_ZERO); |
1642 | loc = (int*)va; | | 1641 | loc = (int*)va; |
1643 | | | 1642 | |
1644 | pmap_extract(pmap_kernel(), va, &pa); | | 1643 | pmap_extract(pmap_kernel(), va, &pa); |
1645 | pg = PHYS_TO_VM_PAGE(pa); | | 1644 | pg = PHYS_TO_VM_PAGE(pa); |
1646 | pmap_unwire(pmap_kernel(), va); | | 1645 | pmap_unwire(pmap_kernel(), va); |
1647 | | | 1646 | |
1648 | pmap_kremove(va, PAGE_SIZE); | | 1647 | pmap_kremove(va, PAGE_SIZE); |
1649 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); | | 1648 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); |
1650 | pmap_update(pmap_kernel()); | | 1649 | pmap_update(pmap_kernel()); |
1651 | | | 1650 | |
1652 | /* Now clear reference and modify */ | | 1651 | /* Now clear reference and modify */ |
1653 | ref = pmap_clear_reference(pg); | | 1652 | ref = pmap_clear_reference(pg); |
1654 | mod = pmap_clear_modify(pg); | | 1653 | mod = pmap_clear_modify(pg); |
1655 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1654 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1656 | (void *)(u_long)va, (long)pa, | | 1655 | (void *)(u_long)va, (long)pa, |
1657 | ref, mod); | | 1656 | ref, mod); |
1658 | | | 1657 | |
1659 | /* Check it's properly cleared */ | | 1658 | /* Check it's properly cleared */ |
1660 | ref = pmap_is_referenced(pg); | | 1659 | ref = pmap_is_referenced(pg); |
1661 | mod = pmap_is_modified(pg); | | 1660 | mod = pmap_is_modified(pg); |
1662 | printf("Checking cleared page: ref %d, mod %d\n", | | 1661 | printf("Checking cleared page: ref %d, mod %d\n", |
1663 | ref, mod); | | 1662 | ref, mod); |
1664 | | | 1663 | |
1665 | /* Reference page */ | | 1664 | /* Reference page */ |
1666 | val = *loc; | | 1665 | val = *loc; |
1667 | | | 1666 | |
1668 | ref = pmap_is_referenced(pg); | | 1667 | ref = pmap_is_referenced(pg); |
1669 | mod = pmap_is_modified(pg); | | 1668 | mod = pmap_is_modified(pg); |
1670 | printf("Referenced page: ref %d, mod %d val %x\n", | | 1669 | printf("Referenced page: ref %d, mod %d val %x\n", |
1671 | ref, mod, val); | | 1670 | ref, mod, val); |
1672 | | | 1671 | |
1673 | /* Now clear reference and modify */ | | 1672 | /* Now clear reference and modify */ |
1674 | ref = pmap_clear_reference(pg); | | 1673 | ref = pmap_clear_reference(pg); |
1675 | mod = pmap_clear_modify(pg); | | 1674 | mod = pmap_clear_modify(pg); |
1676 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1675 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1677 | (void *)(u_long)va, (long)pa, | | 1676 | (void *)(u_long)va, (long)pa, |
1678 | ref, mod); | | 1677 | ref, mod); |
1679 | | | 1678 | |
1680 | /* Modify page */ | | 1679 | /* Modify page */ |
1681 | *loc = 1; | | 1680 | *loc = 1; |
1682 | | | 1681 | |
1683 | ref = pmap_is_referenced(pg); | | 1682 | ref = pmap_is_referenced(pg); |
1684 | mod = pmap_is_modified(pg); | | 1683 | mod = pmap_is_modified(pg); |
1685 | printf("Modified page: ref %d, mod %d\n", | | 1684 | printf("Modified page: ref %d, mod %d\n", |
1686 | ref, mod); | | 1685 | ref, mod); |
1687 | | | 1686 | |
1688 | /* Now clear reference and modify */ | | 1687 | /* Now clear reference and modify */ |
1689 | ref = pmap_clear_reference(pg); | | 1688 | ref = pmap_clear_reference(pg); |
1690 | mod = pmap_clear_modify(pg); | | 1689 | mod = pmap_clear_modify(pg); |
1691 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1690 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1692 | (void *)(u_long)va, (long)pa, | | 1691 | (void *)(u_long)va, (long)pa, |
1693 | ref, mod); | | 1692 | ref, mod); |
1694 | | | 1693 | |
1695 | /* Check it's properly cleared */ | | 1694 | /* Check it's properly cleared */ |
1696 | ref = pmap_is_referenced(pg); | | 1695 | ref = pmap_is_referenced(pg); |
1697 | mod = pmap_is_modified(pg); | | 1696 | mod = pmap_is_modified(pg); |
1698 | printf("Checking cleared page: ref %d, mod %d\n", | | 1697 | printf("Checking cleared page: ref %d, mod %d\n", |
1699 | ref, mod); | | 1698 | ref, mod); |
1700 | | | 1699 | |
1701 | /* Modify page */ | | 1700 | /* Modify page */ |
1702 | *loc = 1; | | 1701 | *loc = 1; |
1703 | | | 1702 | |
1704 | ref = pmap_is_referenced(pg); | | 1703 | ref = pmap_is_referenced(pg); |
1705 | mod = pmap_is_modified(pg); | | 1704 | mod = pmap_is_modified(pg); |
1706 | printf("Modified page: ref %d, mod %d\n", | | 1705 | printf("Modified page: ref %d, mod %d\n", |
1707 | ref, mod); | | 1706 | ref, mod); |
1708 | | | 1707 | |
1709 | /* Check pmap_protect() */ | | 1708 | /* Check pmap_protect() */ |
1710 | pmap_protect(pmap_kernel(), va, va+1, VM_PROT_READ); | | 1709 | pmap_protect(pmap_kernel(), va, va+1, VM_PROT_READ); |
1711 | pmap_update(pmap_kernel()); | | 1710 | pmap_update(pmap_kernel()); |
1712 | ref = pmap_is_referenced(pg); | | 1711 | ref = pmap_is_referenced(pg); |
1713 | mod = pmap_is_modified(pg); | | 1712 | mod = pmap_is_modified(pg); |
1714 | printf("pmap_protect(VM_PROT_READ): ref %d, mod %d\n", | | 1713 | printf("pmap_protect(VM_PROT_READ): ref %d, mod %d\n", |
1715 | ref, mod); | | 1714 | ref, mod); |
1716 | | | 1715 | |
1717 | /* Now clear reference and modify */ | | 1716 | /* Now clear reference and modify */ |
1718 | ref = pmap_clear_reference(pg); | | 1717 | ref = pmap_clear_reference(pg); |
1719 | mod = pmap_clear_modify(pg); | | 1718 | mod = pmap_clear_modify(pg); |
1720 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1719 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1721 | (void *)(u_long)va, (long)pa, | | 1720 | (void *)(u_long)va, (long)pa, |
1722 | ref, mod); | | 1721 | ref, mod); |
1723 | | | 1722 | |
1724 | /* Reference page */ | | 1723 | /* Reference page */ |
1725 | val = *loc; | | 1724 | val = *loc; |
1726 | | | 1725 | |
1727 | ref = pmap_is_referenced(pg); | | 1726 | ref = pmap_is_referenced(pg); |
1728 | mod = pmap_is_modified(pg); | | 1727 | mod = pmap_is_modified(pg); |
1729 | printf("Referenced page: ref %d, mod %d val %x\n", | | 1728 | printf("Referenced page: ref %d, mod %d val %x\n", |
1730 | ref, mod, val); | | 1729 | ref, mod, val); |
1731 | | | 1730 | |
1732 | /* Now clear reference and modify */ | | 1731 | /* Now clear reference and modify */ |
1733 | ref = pmap_clear_reference(pg); | | 1732 | ref = pmap_clear_reference(pg); |
1734 | mod = pmap_clear_modify(pg); | | 1733 | mod = pmap_clear_modify(pg); |
1735 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1734 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1736 | (void *)(u_long)va, (long)pa, | | 1735 | (void *)(u_long)va, (long)pa, |
1737 | ref, mod); | | 1736 | ref, mod); |
1738 | | | 1737 | |
1739 | /* Modify page */ | | 1738 | /* Modify page */ |
1740 | #if 0 | | 1739 | #if 0 |
1741 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); | | 1740 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); |
1742 | pmap_update(pmap_kernel()); | | 1741 | pmap_update(pmap_kernel()); |
1743 | #endif | | 1742 | #endif |
1744 | *loc = 1; | | 1743 | *loc = 1; |
1745 | | | 1744 | |
1746 | ref = pmap_is_referenced(pg); | | 1745 | ref = pmap_is_referenced(pg); |
1747 | mod = pmap_is_modified(pg); | | 1746 | mod = pmap_is_modified(pg); |
1748 | printf("Modified page: ref %d, mod %d\n", | | 1747 | printf("Modified page: ref %d, mod %d\n", |
1749 | ref, mod); | | 1748 | ref, mod); |
1750 | | | 1749 | |
1751 | /* Check pmap_protect() */ | | 1750 | /* Check pmap_protect() */ |
1752 | pmap_protect(pmap_kernel(), va, va+1, VM_PROT_NONE); | | 1751 | pmap_protect(pmap_kernel(), va, va+1, VM_PROT_NONE); |
1753 | pmap_update(pmap_kernel()); | | 1752 | pmap_update(pmap_kernel()); |
1754 | ref = pmap_is_referenced(pg); | | 1753 | ref = pmap_is_referenced(pg); |
1755 | mod = pmap_is_modified(pg); | | 1754 | mod = pmap_is_modified(pg); |
1756 | printf("pmap_protect(): ref %d, mod %d\n", | | 1755 | printf("pmap_protect(): ref %d, mod %d\n", |
1757 | ref, mod); | | 1756 | ref, mod); |
1758 | | | 1757 | |
1759 | /* Now clear reference and modify */ | | 1758 | /* Now clear reference and modify */ |
1760 | ref = pmap_clear_reference(pg); | | 1759 | ref = pmap_clear_reference(pg); |
1761 | mod = pmap_clear_modify(pg); | | 1760 | mod = pmap_clear_modify(pg); |
1762 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1761 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1763 | (void *)(u_long)va, (long)pa, | | 1762 | (void *)(u_long)va, (long)pa, |
1764 | ref, mod); | | 1763 | ref, mod); |
1765 | | | 1764 | |
1766 | /* Reference page */ | | 1765 | /* Reference page */ |
1767 | val = *loc; | | 1766 | val = *loc; |
1768 | | | 1767 | |
1769 | ref = pmap_is_referenced(pg); | | 1768 | ref = pmap_is_referenced(pg); |
1770 | mod = pmap_is_modified(pg); | | 1769 | mod = pmap_is_modified(pg); |
1771 | printf("Referenced page: ref %d, mod %d val %x\n", | | 1770 | printf("Referenced page: ref %d, mod %d val %x\n", |
1772 | ref, mod, val); | | 1771 | ref, mod, val); |
1773 | | | 1772 | |
1774 | /* Now clear reference and modify */ | | 1773 | /* Now clear reference and modify */ |
1775 | ref = pmap_clear_reference(pg); | | 1774 | ref = pmap_clear_reference(pg); |
1776 | mod = pmap_clear_modify(pg); | | 1775 | mod = pmap_clear_modify(pg); |
1777 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1776 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1778 | (void *)(u_long)va, (long)pa, | | 1777 | (void *)(u_long)va, (long)pa, |
1779 | ref, mod); | | 1778 | ref, mod); |
1780 | | | 1779 | |
1781 | /* Modify page */ | | 1780 | /* Modify page */ |
1782 | #if 0 | | 1781 | #if 0 |
1783 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); | | 1782 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); |
1784 | pmap_update(pmap_kernel()); | | 1783 | pmap_update(pmap_kernel()); |
1785 | #endif | | 1784 | #endif |
1786 | *loc = 1; | | 1785 | *loc = 1; |
1787 | | | 1786 | |
1788 | ref = pmap_is_referenced(pg); | | 1787 | ref = pmap_is_referenced(pg); |
1789 | mod = pmap_is_modified(pg); | | 1788 | mod = pmap_is_modified(pg); |
1790 | printf("Modified page: ref %d, mod %d\n", | | 1789 | printf("Modified page: ref %d, mod %d\n", |
1791 | ref, mod); | | 1790 | ref, mod); |
1792 | | | 1791 | |
1793 | /* Check pmap_pag_protect() */ | | 1792 | /* Check pmap_pag_protect() */ |
1794 | pmap_page_protect(pg, VM_PROT_READ); | | 1793 | pmap_page_protect(pg, VM_PROT_READ); |
1795 | ref = pmap_is_referenced(pg); | | 1794 | ref = pmap_is_referenced(pg); |
1796 | mod = pmap_is_modified(pg); | | 1795 | mod = pmap_is_modified(pg); |
1797 | printf("pmap_page_protect(VM_PROT_READ): ref %d, mod %d\n", | | 1796 | printf("pmap_page_protect(VM_PROT_READ): ref %d, mod %d\n", |
1798 | ref, mod); | | 1797 | ref, mod); |
1799 | | | 1798 | |
1800 | /* Now clear reference and modify */ | | 1799 | /* Now clear reference and modify */ |
1801 | ref = pmap_clear_reference(pg); | | 1800 | ref = pmap_clear_reference(pg); |
1802 | mod = pmap_clear_modify(pg); | | 1801 | mod = pmap_clear_modify(pg); |
1803 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1802 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1804 | (void *)(u_long)va, (long)pa, | | 1803 | (void *)(u_long)va, (long)pa, |
1805 | ref, mod); | | 1804 | ref, mod); |
1806 | | | 1805 | |
1807 | /* Reference page */ | | 1806 | /* Reference page */ |
1808 | val = *loc; | | 1807 | val = *loc; |
1809 | | | 1808 | |
1810 | ref = pmap_is_referenced(pg); | | 1809 | ref = pmap_is_referenced(pg); |
1811 | mod = pmap_is_modified(pg); | | 1810 | mod = pmap_is_modified(pg); |
1812 | printf("Referenced page: ref %d, mod %d val %x\n", | | 1811 | printf("Referenced page: ref %d, mod %d val %x\n", |
1813 | ref, mod, val); | | 1812 | ref, mod, val); |
1814 | | | 1813 | |
1815 | /* Now clear reference and modify */ | | 1814 | /* Now clear reference and modify */ |
1816 | ref = pmap_clear_reference(pg); | | 1815 | ref = pmap_clear_reference(pg); |
1817 | mod = pmap_clear_modify(pg); | | 1816 | mod = pmap_clear_modify(pg); |
1818 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1817 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1819 | (void *)(u_long)va, (long)pa, | | 1818 | (void *)(u_long)va, (long)pa, |
1820 | ref, mod); | | 1819 | ref, mod); |
1821 | | | 1820 | |
1822 | /* Modify page */ | | 1821 | /* Modify page */ |
1823 | #if 0 | | 1822 | #if 0 |
1824 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); | | 1823 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); |
1825 | pmap_update(pmap_kernel()); | | 1824 | pmap_update(pmap_kernel()); |
1826 | #endif | | 1825 | #endif |
1827 | *loc = 1; | | 1826 | *loc = 1; |
1828 | | | 1827 | |
1829 | ref = pmap_is_referenced(pg); | | 1828 | ref = pmap_is_referenced(pg); |
1830 | mod = pmap_is_modified(pg); | | 1829 | mod = pmap_is_modified(pg); |
1831 | printf("Modified page: ref %d, mod %d\n", | | 1830 | printf("Modified page: ref %d, mod %d\n", |
1832 | ref, mod); | | 1831 | ref, mod); |
1833 | | | 1832 | |
1834 | /* Check pmap_pag_protect() */ | | 1833 | /* Check pmap_pag_protect() */ |
1835 | pmap_page_protect(pg, VM_PROT_NONE); | | 1834 | pmap_page_protect(pg, VM_PROT_NONE); |
1836 | ref = pmap_is_referenced(pg); | | 1835 | ref = pmap_is_referenced(pg); |
1837 | mod = pmap_is_modified(pg); | | 1836 | mod = pmap_is_modified(pg); |
1838 | printf("pmap_page_protect(): ref %d, mod %d\n", | | 1837 | printf("pmap_page_protect(): ref %d, mod %d\n", |
1839 | ref, mod); | | 1838 | ref, mod); |
1840 | | | 1839 | |
1841 | /* Now clear reference and modify */ | | 1840 | /* Now clear reference and modify */ |
1842 | ref = pmap_clear_reference(pg); | | 1841 | ref = pmap_clear_reference(pg); |
1843 | mod = pmap_clear_modify(pg); | | 1842 | mod = pmap_clear_modify(pg); |
1844 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1843 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1845 | (void *)(u_long)va, (long)pa, | | 1844 | (void *)(u_long)va, (long)pa, |
1846 | ref, mod); | | 1845 | ref, mod); |
1847 | | | 1846 | |
1848 | | | 1847 | |
1849 | /* Reference page */ | | 1848 | /* Reference page */ |
1850 | val = *loc; | | 1849 | val = *loc; |
1851 | | | 1850 | |
1852 | ref = pmap_is_referenced(pg); | | 1851 | ref = pmap_is_referenced(pg); |
1853 | mod = pmap_is_modified(pg); | | 1852 | mod = pmap_is_modified(pg); |
1854 | printf("Referenced page: ref %d, mod %d val %x\n", | | 1853 | printf("Referenced page: ref %d, mod %d val %x\n", |
1855 | ref, mod, val); | | 1854 | ref, mod, val); |
1856 | | | 1855 | |
1857 | /* Now clear reference and modify */ | | 1856 | /* Now clear reference and modify */ |
1858 | ref = pmap_clear_reference(pg); | | 1857 | ref = pmap_clear_reference(pg); |
1859 | mod = pmap_clear_modify(pg); | | 1858 | mod = pmap_clear_modify(pg); |
1860 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1859 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1861 | (void *)(u_long)va, (long)pa, | | 1860 | (void *)(u_long)va, (long)pa, |
1862 | ref, mod); | | 1861 | ref, mod); |
1863 | | | 1862 | |
1864 | /* Modify page */ | | 1863 | /* Modify page */ |
1865 | #if 0 | | 1864 | #if 0 |
1866 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); | | 1865 | pmap_enter(pmap_kernel(), va, pa, VM_PROT_ALL, 0); |
1867 | pmap_update(pmap_kernel()); | | 1866 | pmap_update(pmap_kernel()); |
1868 | #endif | | 1867 | #endif |
1869 | *loc = 1; | | 1868 | *loc = 1; |
1870 | | | 1869 | |
1871 | ref = pmap_is_referenced(pg); | | 1870 | ref = pmap_is_referenced(pg); |
1872 | mod = pmap_is_modified(pg); | | 1871 | mod = pmap_is_modified(pg); |
1873 | printf("Modified page: ref %d, mod %d\n", | | 1872 | printf("Modified page: ref %d, mod %d\n", |
1874 | ref, mod); | | 1873 | ref, mod); |
1875 | | | 1874 | |
1876 | /* Unmap page */ | | 1875 | /* Unmap page */ |
1877 | pmap_remove(pmap_kernel(), va, va+1); | | 1876 | pmap_remove(pmap_kernel(), va, va+1); |
1878 | pmap_update(pmap_kernel()); | | 1877 | pmap_update(pmap_kernel()); |
1879 | ref = pmap_is_referenced(pg); | | 1878 | ref = pmap_is_referenced(pg); |
1880 | mod = pmap_is_modified(pg); | | 1879 | mod = pmap_is_modified(pg); |
1881 | printf("Unmapped page: ref %d, mod %d\n", ref, mod); | | 1880 | printf("Unmapped page: ref %d, mod %d\n", ref, mod); |
1882 | | | 1881 | |
1883 | /* Now clear reference and modify */ | | 1882 | /* Now clear reference and modify */ |
1884 | ref = pmap_clear_reference(pg); | | 1883 | ref = pmap_clear_reference(pg); |
1885 | mod = pmap_clear_modify(pg); | | 1884 | mod = pmap_clear_modify(pg); |
1886 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", | | 1885 | printf("Clearing page va %p pa %lx: ref %d, mod %d\n", |
1887 | (void *)(u_long)va, (long)pa, ref, mod); | | 1886 | (void *)(u_long)va, (long)pa, ref, mod); |
1888 | | | 1887 | |
1889 | /* Check it's properly cleared */ | | 1888 | /* Check it's properly cleared */ |
1890 | ref = pmap_is_referenced(pg); | | 1889 | ref = pmap_is_referenced(pg); |
1891 | mod = pmap_is_modified(pg); | | 1890 | mod = pmap_is_modified(pg); |
1892 | printf("Checking cleared page: ref %d, mod %d\n", | | 1891 | printf("Checking cleared page: ref %d, mod %d\n", |
1893 | ref, mod); | | 1892 | ref, mod); |
1894 | | | 1893 | |
1895 | pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); | | 1894 | pmap_remove(pmap_kernel(), va, va + PAGE_SIZE); |
1896 | pmap_kenter_pa(va, pa, VM_PROT_ALL, 0); | | 1895 | pmap_kenter_pa(va, pa, VM_PROT_ALL, 0); |
1897 | uvm_km_free(kernel_map, (vaddr_t)va, PAGE_SIZE, UVM_KMF_WIRED); | | 1896 | uvm_km_free(kernel_map, (vaddr_t)va, PAGE_SIZE, UVM_KMF_WIRED); |
1898 | } | | 1897 | } |
1899 | #endif | | 1898 | #endif |