source: mainline/arch/mips32/src/mm/tlb.c@ fd3c9e5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fd3c9e5 was fd3c9e5, checked in by Jakub Jermar <jakub@…>, 20 years ago

Small changes to mips32 mm.
Small changes in mm mapping test #1.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (C) 2003-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
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
15 * derived from this software without specific prior written permission.
16 *
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
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <arch/mm/tlb.h>
30#include <arch/mm/asid.h>
31#include <mm/tlb.h>
32#include <mm/page.h>
33#include <mm/vm.h>
34#include <arch/cp0.h>
35#include <panic.h>
36#include <arch.h>
37#include <symtab.h>
38#include <synch/spinlock.h>
39#include <print.h>
40#include <debug.h>
41
42static void tlb_refill_fail(struct exception_regdump *pstate);
43static void tlb_invalid_fail(struct exception_regdump *pstate);
44static void tlb_modified_fail(struct exception_regdump *pstate);
45
46static pte_t *find_mapping_and_check(__address badvaddr);
47static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn);
48
49/** Initialize TLB
50 *
51 * Initialize TLB.
52 * Invalidate all entries and mark wired entries.
53 */
54void tlb_init_arch(void)
55{
56 int i;
57
58 cp0_pagemask_write(TLB_PAGE_MASK_16K);
59 cp0_entry_hi_write(0);
60 cp0_entry_lo0_write(0);
61 cp0_entry_lo1_write(0);
62
63 /*
64 * Invalidate all entries.
65 */
66 for (i = 0; i < TLB_SIZE; i++) {
67 cp0_index_write(i);
68 tlbwi();
69 }
70
71 /*
72 * The kernel is going to make use of some wired
73 * entries (e.g. mapping kernel stacks in kseg3).
74 */
75 cp0_wired_write(TLB_WIRED);
76}
77
78/** Process TLB Refill Exception
79 *
80 * Process TLB Refill Exception.
81 *
82 * @param pstate Interrupted register context.
83 */
84void tlb_refill(struct exception_regdump *pstate)
85{
86 entry_lo_t lo;
87 __address badvaddr;
88 pte_t *pte;
89
90// debug
91 entry_hi_t hi;
92
93 badvaddr = cp0_badvaddr_read();
94
95// debug
96 hi.value = cp0_entry_hi_read();
97 printf("TLB Refill: hi.vnp2=%X\n", hi.vpn2);
98
99 spinlock_lock(&VM->lock);
100 pte = find_mapping_and_check(badvaddr);
101 if (!pte)
102 goto fail;
103
104 /*
105 * Record access to PTE.
106 */
107 pte->a = 1;
108
109 prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
110
111 /*
112 * New entry is to be inserted into TLB
113 */
114 if ((badvaddr/PAGE_SIZE) % 2 == 0) {
115 cp0_entry_lo0_write(lo.value);
116 cp0_entry_lo1_write(0);
117 }
118 else {
119 cp0_entry_lo0_write(0);
120 cp0_entry_lo1_write(lo.value);
121 }
122 tlbwr();
123
124 spinlock_unlock(&VM->lock);
125 return;
126
127fail:
128 spinlock_unlock(&VM->lock);
129 tlb_refill_fail(pstate);
130}
131
132/** Process TLB Invalid Exception
133 *
134 * Process TLB Invalid Exception.
135 *
136 * @param pstate Interrupted register context.
137 */
138void tlb_invalid(struct exception_regdump *pstate)
139{
140 tlb_index_t index;
141 __address badvaddr;
142 entry_lo_t lo;
143 pte_t *pte;
144
145 badvaddr = cp0_badvaddr_read();
146
147 /*
148 * Locate the faulting entry in TLB.
149 */
150 tlbp();
151 index.value = cp0_index_read();
152
153 spinlock_lock(&VM->lock);
154
155 /*
156 * Fail if the entry is not in TLB.
157 */
158 if (index.p) {
159 printf("TLB entry not found.\n");
160 goto fail;
161 }
162
163 pte = find_mapping_and_check(badvaddr);
164 if (!pte)
165 goto fail;
166
167 /*
168 * Read the faulting TLB entry.
169 */
170 tlbr();
171
172 /*
173 * Record access to PTE.
174 */
175 pte->a = 1;
176
177 prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
178
179 /*
180 * The entry is to be updated in TLB.
181 */
182 if ((badvaddr/PAGE_SIZE) % 2 == 0)
183 cp0_entry_lo0_write(lo.value);
184 else
185 cp0_entry_lo1_write(lo.value);
186 tlbwi();
187
188 spinlock_unlock(&VM->lock);
189 return;
190
191fail:
192 spinlock_unlock(&VM->lock);
193 tlb_invalid_fail(pstate);
194}
195
196/** Process TLB Modified Exception
197 *
198 * Process TLB Modified Exception.
199 *
200 * @param pstate Interrupted register context.
201 */
202void tlb_modified(struct exception_regdump *pstate)
203{
204 tlb_index_t index;
205 __address badvaddr;
206 entry_lo_t lo;
207 pte_t *pte;
208
209 badvaddr = cp0_badvaddr_read();
210
211 /*
212 * Locate the faulting entry in TLB.
213 */
214 tlbp();
215 index.value = cp0_index_read();
216
217 spinlock_lock(&VM->lock);
218
219 /*
220 * Fail if the entry is not in TLB.
221 */
222 if (index.p) {
223 printf("TLB entry not found.\n");
224 goto fail;
225 }
226
227 pte = find_mapping_and_check(badvaddr);
228 if (!pte)
229 goto fail;
230
231 /*
232 * Fail if the page is not writable.
233 */
234 if (!pte->w)
235 goto fail;
236
237 /*
238 * Read the faulting TLB entry.
239 */
240 tlbr();
241
242 /*
243 * Record access and write to PTE.
244 */
245 pte->a = 1;
246 pte->d = 1;
247
248 prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
249
250 /*
251 * The entry is to be updated in TLB.
252 */
253 if ((badvaddr/PAGE_SIZE) % 2 == 0)
254 cp0_entry_lo0_write(lo.value);
255 else
256 cp0_entry_lo1_write(lo.value);
257 tlbwi();
258
259 spinlock_unlock(&VM->lock);
260 return;
261
262fail:
263 spinlock_unlock(&VM->lock);
264 tlb_modified_fail(pstate);
265}
266
267void tlb_refill_fail(struct exception_regdump *pstate)
268{
269 char *symbol = "";
270 char *sym2 = "";
271
272 char *s = get_symtab_entry(pstate->epc);
273 if (s)
274 symbol = s;
275 s = get_symtab_entry(pstate->ra);
276 if (s)
277 sym2 = s;
278 panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
279}
280
281
282void tlb_invalid_fail(struct exception_regdump *pstate)
283{
284 char *symbol = "";
285
286 char *s = get_symtab_entry(pstate->epc);
287 if (s)
288 symbol = s;
289 panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
290}
291
292void tlb_modified_fail(struct exception_regdump *pstate)
293{
294 char *symbol = "";
295
296 char *s = get_symtab_entry(pstate->epc);
297 if (s)
298 symbol = s;
299 panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
300}
301
302/** Invalidate TLB entries with specified ASID
303 *
304 * Invalidate TLB entries with specified ASID.
305 *
306 * @param asid ASID.
307 */
308void tlb_invalidate(asid_t asid)
309{
310 entry_hi_t hi;
311 pri_t pri;
312 int i;
313
314 ASSERT(asid != ASID_INVALID);
315
316 pri = cpu_priority_high();
317
318 for (i = 0; i < TLB_SIZE; i++) {
319 cp0_index_write(i);
320 tlbr();
321
322 hi.value = cp0_entry_hi_read();
323 if (hi.asid == asid) {
324 cp0_pagemask_write(TLB_PAGE_MASK_16K);
325 cp0_entry_hi_write(0);
326 cp0_entry_lo0_write(0);
327 cp0_entry_lo1_write(0);
328 tlbwi();
329 }
330 }
331
332 cpu_priority_restore(pri);
333}
334
335/** Try to find PTE for faulting address
336 *
337 * Try to find PTE for faulting address.
338 * The VM->lock must be held on entry to this function.
339 *
340 * @param badvaddr Faulting virtual address.
341 *
342 * @return PTE on success, NULL otherwise.
343 */
344pte_t *find_mapping_and_check(__address badvaddr)
345{
346 entry_hi_t hi;
347 pte_t *pte;
348
349 hi.value = cp0_entry_hi_read();
350
351 /*
352 * Handler cannot succeed if the ASIDs don't match.
353 */
354 if (hi.asid != VM->asid) {
355 printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
356 return NULL;
357 }
358
359 /*
360 * Handler cannot succeed if badvaddr has no mapping.
361 */
362 pte = find_mapping(badvaddr, 0);
363 if (!pte) {
364 printf("No such mapping.\n");
365 return NULL;
366 }
367
368 /*
369 * Handler cannot succeed if the mapping is marked as invalid.
370 */
371 if (!pte->v) {
372 printf("Invalid mapping.\n");
373 return NULL;
374 }
375
376 return pte;
377}
378
379void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
380{
381 lo->g = g;
382 lo->v = v;
383 lo->d = d;
384 lo->c = c;
385 lo->pfn = pfn;
386 lo->zero = 0;
387}
Note: See TracBrowser for help on using the repository browser.