Rev 598 | Rev 612 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 598 | Rev 599 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (C) 2003-2004 Jakub Jermar |
2 | * Copyright (C) 2003-2004 Jakub Jermar |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
13 | * documentation and/or other materials provided with the distribution. |
14 | * - The name of the author may not be used to endorse or promote products |
14 | * - The name of the author may not be used to endorse or promote products |
15 | * derived from this software without specific prior written permission. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | #include <arch/mm/tlb.h> |
29 | #include <arch/mm/tlb.h> |
30 | #include <arch/mm/asid.h> |
30 | #include <arch/mm/asid.h> |
31 | #include <mm/tlb.h> |
31 | #include <mm/tlb.h> |
32 | #include <mm/page.h> |
32 | #include <mm/page.h> |
33 | #include <mm/vm.h> |
33 | #include <mm/vm.h> |
34 | #include <arch/cp0.h> |
34 | #include <arch/cp0.h> |
35 | #include <panic.h> |
35 | #include <panic.h> |
36 | #include <arch.h> |
36 | #include <arch.h> |
37 | #include <symtab.h> |
37 | #include <symtab.h> |
38 | #include <synch/spinlock.h> |
38 | #include <synch/spinlock.h> |
39 | #include <print.h> |
39 | #include <print.h> |
40 | #include <debug.h> |
40 | #include <debug.h> |
41 | 41 | ||
42 | static void tlb_refill_fail(struct exception_regdump *pstate); |
42 | static void tlb_refill_fail(struct exception_regdump *pstate); |
43 | static void tlb_invalid_fail(struct exception_regdump *pstate); |
43 | static void tlb_invalid_fail(struct exception_regdump *pstate); |
44 | static void tlb_modified_fail(struct exception_regdump *pstate); |
44 | static void tlb_modified_fail(struct exception_regdump *pstate); |
45 | 45 | ||
46 | static pte_t *find_mapping_and_check(__address badvaddr); |
46 | static pte_t *find_mapping_and_check(__address badvaddr); |
47 | 47 | ||
48 | static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn); |
48 | static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn); |
49 | static void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr); |
49 | static void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr); |
50 | 50 | ||
51 | /** Initialize TLB |
51 | /** Initialize TLB |
52 | * |
52 | * |
53 | * Initialize TLB. |
53 | * Initialize TLB. |
54 | * Invalidate all entries and mark wired entries. |
54 | * Invalidate all entries and mark wired entries. |
55 | */ |
55 | */ |
56 | void tlb_arch_init(void) |
56 | void tlb_arch_init(void) |
57 | { |
57 | { |
- | 58 | int i; |
|
- | 59 | ||
58 | cp0_pagemask_write(TLB_PAGE_MASK_16K); |
60 | cp0_pagemask_write(TLB_PAGE_MASK_16K); |
- | 61 | cp0_entry_hi_write(0); |
|
- | 62 | cp0_entry_lo0_write(0); |
|
- | 63 | cp0_entry_lo1_write(0); |
|
59 | 64 | ||
- | 65 | /* Clear and initialize TLB. */ |
|
- | 66 | ||
- | 67 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
|
60 | tlb_invalidate_all(); |
68 | cp0_index_write(i); |
- | 69 | tlbwi(); |
|
- | 70 | } |
|
61 | 71 | ||
62 | /* |
72 | /* |
63 | * The kernel is going to make use of some wired |
73 | * The kernel is going to make use of some wired |
64 | * entries (e.g. mapping kernel stacks in kseg3). |
74 | * entries (e.g. mapping kernel stacks in kseg3). |
65 | */ |
75 | */ |
66 | cp0_wired_write(TLB_WIRED); |
76 | cp0_wired_write(TLB_WIRED); |
67 | } |
77 | } |
68 | 78 | ||
69 | /** Process TLB Refill Exception |
79 | /** Process TLB Refill Exception |
70 | * |
80 | * |
71 | * Process TLB Refill Exception. |
81 | * Process TLB Refill Exception. |
72 | * |
82 | * |
73 | * @param pstate Interrupted register context. |
83 | * @param pstate Interrupted register context. |
74 | */ |
84 | */ |
75 | void tlb_refill(struct exception_regdump *pstate) |
85 | void tlb_refill(struct exception_regdump *pstate) |
76 | { |
86 | { |
77 | entry_lo_t lo; |
87 | entry_lo_t lo; |
78 | entry_hi_t hi; |
88 | entry_hi_t hi; |
79 | __address badvaddr; |
89 | __address badvaddr; |
80 | pte_t *pte; |
90 | pte_t *pte; |
81 | 91 | ||
82 | badvaddr = cp0_badvaddr_read(); |
92 | badvaddr = cp0_badvaddr_read(); |
83 | 93 | ||
84 | spinlock_lock(&VM->lock); |
94 | spinlock_lock(&VM->lock); |
85 | 95 | ||
86 | pte = find_mapping_and_check(badvaddr); |
96 | pte = find_mapping_and_check(badvaddr); |
87 | if (!pte) |
97 | if (!pte) |
88 | goto fail; |
98 | goto fail; |
89 | 99 | ||
90 | /* |
100 | /* |
91 | * Record access to PTE. |
101 | * Record access to PTE. |
92 | */ |
102 | */ |
93 | pte->a = 1; |
103 | pte->a = 1; |
94 | 104 | ||
95 | prepare_entry_hi(&hi, VM->asid, badvaddr); |
105 | prepare_entry_hi(&hi, VM->asid, badvaddr); |
96 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn); |
106 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn); |
97 | 107 | ||
98 | /* |
108 | /* |
99 | * New entry is to be inserted into TLB |
109 | * New entry is to be inserted into TLB |
100 | */ |
110 | */ |
101 | cp0_entry_hi_write(hi.value); |
111 | cp0_entry_hi_write(hi.value); |
102 | if ((badvaddr/PAGE_SIZE) % 2 == 0) { |
112 | if ((badvaddr/PAGE_SIZE) % 2 == 0) { |
103 | cp0_entry_lo0_write(lo.value); |
113 | cp0_entry_lo0_write(lo.value); |
104 | cp0_entry_lo1_write(0); |
114 | cp0_entry_lo1_write(0); |
105 | } |
115 | } |
106 | else { |
116 | else { |
107 | cp0_entry_lo0_write(0); |
117 | cp0_entry_lo0_write(0); |
108 | cp0_entry_lo1_write(lo.value); |
118 | cp0_entry_lo1_write(lo.value); |
109 | } |
119 | } |
110 | tlbwr(); |
120 | tlbwr(); |
111 | 121 | ||
112 | spinlock_unlock(&VM->lock); |
122 | spinlock_unlock(&VM->lock); |
113 | return; |
123 | return; |
114 | 124 | ||
115 | fail: |
125 | fail: |
116 | spinlock_unlock(&VM->lock); |
126 | spinlock_unlock(&VM->lock); |
117 | tlb_refill_fail(pstate); |
127 | tlb_refill_fail(pstate); |
118 | } |
128 | } |
119 | 129 | ||
120 | /** Process TLB Invalid Exception |
130 | /** Process TLB Invalid Exception |
121 | * |
131 | * |
122 | * Process TLB Invalid Exception. |
132 | * Process TLB Invalid Exception. |
123 | * |
133 | * |
124 | * @param pstate Interrupted register context. |
134 | * @param pstate Interrupted register context. |
125 | */ |
135 | */ |
126 | void tlb_invalid(struct exception_regdump *pstate) |
136 | void tlb_invalid(struct exception_regdump *pstate) |
127 | { |
137 | { |
128 | tlb_index_t index; |
138 | tlb_index_t index; |
129 | __address badvaddr; |
139 | __address badvaddr; |
130 | entry_lo_t lo; |
140 | entry_lo_t lo; |
131 | entry_hi_t hi; |
141 | entry_hi_t hi; |
132 | pte_t *pte; |
142 | pte_t *pte; |
133 | 143 | ||
134 | badvaddr = cp0_badvaddr_read(); |
144 | badvaddr = cp0_badvaddr_read(); |
135 | 145 | ||
136 | /* |
146 | /* |
137 | * Locate the faulting entry in TLB. |
147 | * Locate the faulting entry in TLB. |
138 | */ |
148 | */ |
139 | hi.value = cp0_entry_hi_read(); |
149 | hi.value = cp0_entry_hi_read(); |
140 | prepare_entry_hi(&hi, hi.asid, badvaddr); |
150 | prepare_entry_hi(&hi, hi.asid, badvaddr); |
141 | cp0_entry_hi_write(hi.value); |
151 | cp0_entry_hi_write(hi.value); |
142 | tlbp(); |
152 | tlbp(); |
143 | index.value = cp0_index_read(); |
153 | index.value = cp0_index_read(); |
144 | 154 | ||
145 | spinlock_lock(&VM->lock); |
155 | spinlock_lock(&VM->lock); |
146 | 156 | ||
147 | /* |
157 | /* |
148 | * Fail if the entry is not in TLB. |
158 | * Fail if the entry is not in TLB. |
149 | */ |
159 | */ |
150 | if (index.p) { |
160 | if (index.p) { |
151 | printf("TLB entry not found.\n"); |
161 | printf("TLB entry not found.\n"); |
152 | goto fail; |
162 | goto fail; |
153 | } |
163 | } |
154 | 164 | ||
155 | pte = find_mapping_and_check(badvaddr); |
165 | pte = find_mapping_and_check(badvaddr); |
156 | if (!pte) |
166 | if (!pte) |
157 | goto fail; |
167 | goto fail; |
158 | 168 | ||
159 | /* |
169 | /* |
160 | * Read the faulting TLB entry. |
170 | * Read the faulting TLB entry. |
161 | */ |
171 | */ |
162 | tlbr(); |
172 | tlbr(); |
163 | 173 | ||
164 | /* |
174 | /* |
165 | * Record access to PTE. |
175 | * Record access to PTE. |
166 | */ |
176 | */ |
167 | pte->a = 1; |
177 | pte->a = 1; |
168 | 178 | ||
169 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn); |
179 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn); |
170 | 180 | ||
171 | /* |
181 | /* |
172 | * The entry is to be updated in TLB. |
182 | * The entry is to be updated in TLB. |
173 | */ |
183 | */ |
174 | if ((badvaddr/PAGE_SIZE) % 2 == 0) |
184 | if ((badvaddr/PAGE_SIZE) % 2 == 0) |
175 | cp0_entry_lo0_write(lo.value); |
185 | cp0_entry_lo0_write(lo.value); |
176 | else |
186 | else |
177 | cp0_entry_lo1_write(lo.value); |
187 | cp0_entry_lo1_write(lo.value); |
178 | tlbwi(); |
188 | tlbwi(); |
179 | 189 | ||
180 | spinlock_unlock(&VM->lock); |
190 | spinlock_unlock(&VM->lock); |
181 | return; |
191 | return; |
182 | 192 | ||
183 | fail: |
193 | fail: |
184 | spinlock_unlock(&VM->lock); |
194 | spinlock_unlock(&VM->lock); |
185 | tlb_invalid_fail(pstate); |
195 | tlb_invalid_fail(pstate); |
186 | } |
196 | } |
187 | 197 | ||
188 | /** Process TLB Modified Exception |
198 | /** Process TLB Modified Exception |
189 | * |
199 | * |
190 | * Process TLB Modified Exception. |
200 | * Process TLB Modified Exception. |
191 | * |
201 | * |
192 | * @param pstate Interrupted register context. |
202 | * @param pstate Interrupted register context. |
193 | */ |
203 | */ |
194 | void tlb_modified(struct exception_regdump *pstate) |
204 | void tlb_modified(struct exception_regdump *pstate) |
195 | { |
205 | { |
196 | tlb_index_t index; |
206 | tlb_index_t index; |
197 | __address badvaddr; |
207 | __address badvaddr; |
198 | entry_lo_t lo; |
208 | entry_lo_t lo; |
199 | entry_hi_t hi; |
209 | entry_hi_t hi; |
200 | pte_t *pte; |
210 | pte_t *pte; |
201 | 211 | ||
202 | badvaddr = cp0_badvaddr_read(); |
212 | badvaddr = cp0_badvaddr_read(); |
203 | 213 | ||
204 | /* |
214 | /* |
205 | * Locate the faulting entry in TLB. |
215 | * Locate the faulting entry in TLB. |
206 | */ |
216 | */ |
207 | hi.value = cp0_entry_hi_read(); |
217 | hi.value = cp0_entry_hi_read(); |
208 | prepare_entry_hi(&hi, hi.asid, badvaddr); |
218 | prepare_entry_hi(&hi, hi.asid, badvaddr); |
209 | cp0_entry_hi_write(hi.value); |
219 | cp0_entry_hi_write(hi.value); |
210 | tlbp(); |
220 | tlbp(); |
211 | index.value = cp0_index_read(); |
221 | index.value = cp0_index_read(); |
212 | 222 | ||
213 | spinlock_lock(&VM->lock); |
223 | spinlock_lock(&VM->lock); |
214 | 224 | ||
215 | /* |
225 | /* |
216 | * Fail if the entry is not in TLB. |
226 | * Fail if the entry is not in TLB. |
217 | */ |
227 | */ |
218 | if (index.p) { |
228 | if (index.p) { |
219 | printf("TLB entry not found.\n"); |
229 | printf("TLB entry not found.\n"); |
220 | goto fail; |
230 | goto fail; |
221 | } |
231 | } |
222 | 232 | ||
223 | pte = find_mapping_and_check(badvaddr); |
233 | pte = find_mapping_and_check(badvaddr); |
224 | if (!pte) |
234 | if (!pte) |
225 | goto fail; |
235 | goto fail; |
226 | 236 | ||
227 | /* |
237 | /* |
228 | * Fail if the page is not writable. |
238 | * Fail if the page is not writable. |
229 | */ |
239 | */ |
230 | if (!pte->w) |
240 | if (!pte->w) |
231 | goto fail; |
241 | goto fail; |
232 | 242 | ||
233 | /* |
243 | /* |
234 | * Read the faulting TLB entry. |
244 | * Read the faulting TLB entry. |
235 | */ |
245 | */ |
236 | tlbr(); |
246 | tlbr(); |
237 | 247 | ||
238 | /* |
248 | /* |
239 | * Record access and write to PTE. |
249 | * Record access and write to PTE. |
240 | */ |
250 | */ |
241 | pte->a = 1; |
251 | pte->a = 1; |
242 | pte->lo.d = 1; |
252 | pte->lo.d = 1; |
243 | 253 | ||
244 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->w, pte->lo.c, pte->lo.pfn); |
254 | prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->w, pte->lo.c, pte->lo.pfn); |
245 | 255 | ||
246 | /* |
256 | /* |
247 | * The entry is to be updated in TLB. |
257 | * The entry is to be updated in TLB. |
248 | */ |
258 | */ |
249 | if ((badvaddr/PAGE_SIZE) % 2 == 0) |
259 | if ((badvaddr/PAGE_SIZE) % 2 == 0) |
250 | cp0_entry_lo0_write(lo.value); |
260 | cp0_entry_lo0_write(lo.value); |
251 | else |
261 | else |
252 | cp0_entry_lo1_write(lo.value); |
262 | cp0_entry_lo1_write(lo.value); |
253 | tlbwi(); |
263 | tlbwi(); |
254 | 264 | ||
255 | spinlock_unlock(&VM->lock); |
265 | spinlock_unlock(&VM->lock); |
256 | return; |
266 | return; |
257 | 267 | ||
258 | fail: |
268 | fail: |
259 | spinlock_unlock(&VM->lock); |
269 | spinlock_unlock(&VM->lock); |
260 | tlb_modified_fail(pstate); |
270 | tlb_modified_fail(pstate); |
261 | } |
271 | } |
262 | 272 | ||
263 | void tlb_refill_fail(struct exception_regdump *pstate) |
273 | void tlb_refill_fail(struct exception_regdump *pstate) |
264 | { |
274 | { |
265 | char *symbol = ""; |
275 | char *symbol = ""; |
266 | char *sym2 = ""; |
276 | char *sym2 = ""; |
267 | 277 | ||
268 | char *s = get_symtab_entry(pstate->epc); |
278 | char *s = get_symtab_entry(pstate->epc); |
269 | if (s) |
279 | if (s) |
270 | symbol = s; |
280 | symbol = s; |
271 | s = get_symtab_entry(pstate->ra); |
281 | s = get_symtab_entry(pstate->ra); |
272 | if (s) |
282 | if (s) |
273 | sym2 = s; |
283 | sym2 = s; |
274 | panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2); |
284 | panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2); |
275 | } |
285 | } |
276 | 286 | ||
277 | 287 | ||
278 | void tlb_invalid_fail(struct exception_regdump *pstate) |
288 | void tlb_invalid_fail(struct exception_regdump *pstate) |
279 | { |
289 | { |
280 | char *symbol = ""; |
290 | char *symbol = ""; |
281 | 291 | ||
282 | char *s = get_symtab_entry(pstate->epc); |
292 | char *s = get_symtab_entry(pstate->epc); |
283 | if (s) |
293 | if (s) |
284 | symbol = s; |
294 | symbol = s; |
285 | panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol); |
295 | panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol); |
286 | } |
296 | } |
287 | 297 | ||
288 | void tlb_modified_fail(struct exception_regdump *pstate) |
298 | void tlb_modified_fail(struct exception_regdump *pstate) |
289 | { |
299 | { |
290 | char *symbol = ""; |
300 | char *symbol = ""; |
291 | 301 | ||
292 | char *s = get_symtab_entry(pstate->epc); |
302 | char *s = get_symtab_entry(pstate->epc); |
293 | if (s) |
303 | if (s) |
294 | symbol = s; |
304 | symbol = s; |
295 | panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol); |
305 | panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol); |
296 | } |
306 | } |
297 | 307 | ||
298 | /** Invalidate TLB entries with specified ASID |
- | |
299 | * |
- | |
300 | * Invalidate TLB entries with specified ASID. |
- | |
301 | * |
- | |
302 | * @param asid ASID. |
- | |
303 | */ |
- | |
304 | void tlb_invalidate(asid_t asid) |
- | |
305 | { |
- | |
306 | entry_hi_t hi; |
- | |
307 | ipl_t ipl; |
- | |
308 | int i; |
- | |
309 | - | ||
310 | ASSERT(asid != ASID_INVALID); |
- | |
311 | - | ||
312 | ipl = interrupts_disable(); |
- | |
313 | - | ||
314 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
- | |
315 | cp0_index_write(i); |
- | |
316 | tlbr(); |
- | |
317 | - | ||
318 | hi.value = cp0_entry_hi_read(); |
- | |
319 | if (hi.asid == asid) { |
- | |
320 | cp0_pagemask_write(TLB_PAGE_MASK_16K); |
- | |
321 | cp0_entry_hi_write(0); |
- | |
322 | cp0_entry_lo0_write(0); |
- | |
323 | cp0_entry_lo1_write(0); |
- | |
324 | tlbwi(); |
- | |
325 | } |
- | |
326 | } |
- | |
327 | - | ||
328 | interrupts_restore(ipl); |
- | |
329 | } |
- | |
330 | - | ||
331 | /** Try to find PTE for faulting address |
308 | /** Try to find PTE for faulting address |
332 | * |
309 | * |
333 | * Try to find PTE for faulting address. |
310 | * Try to find PTE for faulting address. |
334 | * The VM->lock must be held on entry to this function. |
311 | * The VM->lock must be held on entry to this function. |
335 | * |
312 | * |
336 | * @param badvaddr Faulting virtual address. |
313 | * @param badvaddr Faulting virtual address. |
337 | * |
314 | * |
338 | * @return PTE on success, NULL otherwise. |
315 | * @return PTE on success, NULL otherwise. |
339 | */ |
316 | */ |
340 | pte_t *find_mapping_and_check(__address badvaddr) |
317 | pte_t *find_mapping_and_check(__address badvaddr) |
341 | { |
318 | { |
342 | entry_hi_t hi; |
319 | entry_hi_t hi; |
343 | pte_t *pte; |
320 | pte_t *pte; |
344 | 321 | ||
345 | hi.value = cp0_entry_hi_read(); |
322 | hi.value = cp0_entry_hi_read(); |
346 | 323 | ||
347 | /* |
324 | /* |
348 | * Handler cannot succeed if the ASIDs don't match. |
325 | * Handler cannot succeed if the ASIDs don't match. |
349 | */ |
326 | */ |
350 | if (hi.asid != VM->asid) { |
327 | if (hi.asid != VM->asid) { |
351 | printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid); |
328 | printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid); |
352 | return NULL; |
329 | return NULL; |
353 | } |
330 | } |
354 | 331 | ||
355 | /* |
332 | /* |
356 | * Handler cannot succeed if badvaddr has no mapping. |
333 | * Handler cannot succeed if badvaddr has no mapping. |
357 | */ |
334 | */ |
358 | pte = page_mapping_find(badvaddr, 0); |
335 | pte = page_mapping_find(badvaddr, 0); |
359 | if (!pte) { |
336 | if (!pte) { |
360 | printf("No such mapping.\n"); |
337 | printf("No such mapping.\n"); |
361 | return NULL; |
338 | return NULL; |
362 | } |
339 | } |
363 | 340 | ||
364 | /* |
341 | /* |
365 | * Handler cannot succeed if the mapping is marked as invalid. |
342 | * Handler cannot succeed if the mapping is marked as invalid. |
366 | */ |
343 | */ |
367 | if (!pte->lo.v) { |
344 | if (!pte->lo.v) { |
368 | printf("Invalid mapping.\n"); |
345 | printf("Invalid mapping.\n"); |
369 | return NULL; |
346 | return NULL; |
370 | } |
347 | } |
371 | 348 | ||
372 | return pte; |
349 | return pte; |
373 | } |
350 | } |
374 | 351 | ||
375 | void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn) |
352 | void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn) |
376 | { |
353 | { |
377 | lo->value = 0; |
354 | lo->value = 0; |
378 | lo->g = g; |
355 | lo->g = g; |
379 | lo->v = v; |
356 | lo->v = v; |
380 | lo->d = d; |
357 | lo->d = d; |
381 | lo->c = c; |
358 | lo->c = c; |
382 | lo->pfn = pfn; |
359 | lo->pfn = pfn; |
383 | } |
360 | } |
384 | 361 | ||
385 | void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr) |
362 | void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr) |
386 | { |
363 | { |
387 | hi->value = (((addr/PAGE_SIZE)/2)*PAGE_SIZE*2); |
364 | hi->value = (((addr/PAGE_SIZE)/2)*PAGE_SIZE*2); |
388 | hi->asid = asid; |
365 | hi->asid = asid; |
389 | } |
366 | } |
390 | 367 | ||
391 | /** Print contents of TLB. */ |
368 | /** Print contents of TLB. */ |
392 | void tlb_print(void) |
369 | void tlb_print(void) |
393 | { |
370 | { |
394 | entry_lo_t lo0, lo1; |
371 | entry_lo_t lo0, lo1; |
395 | entry_hi_t hi; |
372 | entry_hi_t hi; |
396 | int i; |
373 | int i; |
397 | 374 | ||
398 | printf("TLB:\n"); |
375 | printf("TLB:\n"); |
399 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
376 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
400 | cp0_index_write(i); |
377 | cp0_index_write(i); |
401 | tlbr(); |
378 | tlbr(); |
402 | 379 | ||
403 | hi.value = cp0_entry_hi_read(); |
380 | hi.value = cp0_entry_hi_read(); |
404 | lo0.value = cp0_entry_lo0_read(); |
381 | lo0.value = cp0_entry_lo0_read(); |
405 | lo1.value = cp0_entry_lo1_read(); |
382 | lo1.value = cp0_entry_lo1_read(); |
406 | 383 | ||
407 | printf("%d: asid=%d, vpn2=%d\tg[0]=%d, v[0]=%d, d[0]=%d, c[0]=%B, pfn[0]=%d\n" |
384 | printf("%d: asid=%d, vpn2=%d\tg[0]=%d, v[0]=%d, d[0]=%d, c[0]=%B, pfn[0]=%d\n" |
408 | "\t\t\tg[1]=%d, v[1]=%d, d[1]=%d, c[1]=%B, pfn[1]=%d\n", |
385 | "\t\t\tg[1]=%d, v[1]=%d, d[1]=%d, c[1]=%B, pfn[1]=%d\n", |
409 | i, hi.asid, hi.vpn2, lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn, |
386 | i, hi.asid, hi.vpn2, lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn, |
410 | lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn); |
387 | lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn); |
411 | } |
388 | } |
412 | } |
389 | } |
413 | 390 | ||
414 | /** Invalidate all TLB entries. */ |
391 | /** Invalidate all TLB entries. */ |
415 | void tlb_invalidate_all(void) |
392 | void tlb_invalidate_all(void) |
416 | { |
393 | { |
- | 394 | ipl_t ipl; |
|
- | 395 | entry_lo_t lo0, lo1; |
|
417 | int i; |
396 | int i; |
418 | 397 | ||
419 | cp0_entry_hi_write(0); |
- | |
420 | cp0_entry_lo0_write(0); |
- | |
421 | cp0_entry_lo1_write(0); |
398 | ipl = interrupts_disable(); |
422 | 399 | ||
423 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
400 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
424 | cp0_index_write(i); |
401 | cp0_index_write(i); |
- | 402 | tlbr(); |
|
- | 403 | ||
- | 404 | lo0.value = cp0_entry_lo0_read(); |
|
- | 405 | lo1.value = cp0_entry_lo1_read(); |
|
- | 406 | ||
- | 407 | lo0.v = 0; |
|
- | 408 | lo1.v = 0; |
|
- | 409 | ||
- | 410 | cp0_entry_lo0_write(lo0.value); |
|
- | 411 | cp0_entry_lo1_write(lo1.value); |
|
- | 412 | ||
425 | tlbwi(); |
413 | tlbwi(); |
426 | } |
414 | } |
- | 415 | ||
- | 416 | interrupts_restore(ipl); |
|
427 | } |
417 | } |
428 | 418 | ||
429 | /** Invalidate all TLB entries belonging to specified address space. |
419 | /** Invalidate all TLB entries belonging to specified address space. |
430 | * |
420 | * |
431 | * @param asid Address space identifier. |
421 | * @param asid Address space identifier. |
432 | */ |
422 | */ |
433 | void tlb_invalidate_asid(asid_t asid) |
423 | void tlb_invalidate_asid(asid_t asid) |
434 | { |
424 | { |
- | 425 | ipl_t ipl; |
|
- | 426 | entry_lo_t lo0, lo1; |
|
435 | entry_hi_t hi; |
427 | entry_hi_t hi; |
436 | int i; |
428 | int i; |
437 | 429 | ||
- | 430 | ASSERT(asid != ASID_INVALID); |
|
- | 431 | ||
- | 432 | ipl = interrupts_disable(); |
|
- | 433 | ||
438 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
434 | for (i = 0; i < TLB_ENTRY_COUNT; i++) { |
439 | cp0_index_write(i); |
435 | cp0_index_write(i); |
440 | tlbr(); |
436 | tlbr(); |
441 | 437 | ||
- | 438 | hi.value = cp0_entry_hi_read(); |
|
- | 439 | ||
442 | if (hi.asid == asid) { |
440 | if (hi.asid == asid) { |
- | 441 | lo0.value = cp0_entry_lo0_read(); |
|
- | 442 | lo1.value = cp0_entry_lo1_read(); |
|
- | 443 | ||
- | 444 | lo0.v = 0; |
|
- | 445 | lo1.v = 0; |
|
- | 446 | ||
443 | cp0_entry_lo0_write(0); |
447 | cp0_entry_lo0_write(lo0.value); |
444 | cp0_entry_lo1_write(0); |
448 | cp0_entry_lo1_write(lo1.value); |
- | 449 | ||
445 | tlbwi(); |
450 | tlbwi(); |
446 | } |
451 | } |
447 | } |
452 | } |
448 | 453 | ||
- | 454 | interrupts_restore(ipl); |
|
449 | } |
455 | } |
450 | 456 | ||
451 | /** Invalidate TLB entry for specified page belonging to specified address space. |
457 | /** Invalidate TLB entry for specified page belonging to specified address space. |
452 | * |
458 | * |
453 | * @param asid Address space identifier. |
459 | * @param asid Address space identifier. |
454 | * @param page Page whose TLB entry is to be invalidated. |
460 | * @param page Page whose TLB entry is to be invalidated. |
455 | */ |
461 | */ |
456 | void tlb_invalidate_page(asid_t asid, __address page) |
462 | void tlb_invalidate_page(asid_t asid, __address page) |
457 | { |
463 | { |
- | 464 | ipl_t ipl; |
|
- | 465 | entry_lo_t lo0, lo1; |
|
458 | entry_hi_t hi; |
466 | entry_hi_t hi; |
459 | tlb_index_t index; |
467 | tlb_index_t index; |
- | 468 | ||
- | 469 | ASSERT(asid != ASID_INVALID); |
|
- | 470 | ||
460 | int i; |
471 | ipl = interrupts_disable(); |
461 | 472 | ||
462 | hi.value = 0; |
473 | hi.value = 0; |
463 | prepare_entry_hi(&hi, asid, page); |
474 | prepare_entry_hi(&hi, asid, page); |
- | 475 | cp0_entry_hi_write(hi.value); |
|
464 | 476 | ||
465 | tlbp(); |
477 | tlbp(); |
466 | index.value = cp0_index_read(); |
478 | index.value = cp0_index_read(); |
467 | 479 | ||
468 | if (!index.p) { |
480 | if (!index.p) { |
469 | /* Entry was found, index register contains valid index. */ |
481 | /* Entry was found, index register contains valid index. */ |
- | 482 | tlbr(); |
|
- | 483 | ||
- | 484 | lo0.value = cp0_entry_lo0_read(); |
|
- | 485 | lo1.value = cp0_entry_lo1_read(); |
|
- | 486 | ||
- | 487 | lo0.v = 0; |
|
- | 488 | lo1.v = 0; |
|
- | 489 | ||
470 | cp0_entry_lo0_write(0); |
490 | cp0_entry_lo0_write(lo0.value); |
471 | cp0_entry_lo1_write(0); |
491 | cp0_entry_lo1_write(lo1.value); |
- | 492 | ||
472 | tlbwi(); |
493 | tlbwi(); |
473 | } |
494 | } |
- | 495 | ||
- | 496 | interrupts_restore(ipl); |
|
474 | } |
497 | } |
475 | 498 |