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
RevLine 
[f761f1eb]1/*
[178ec7b]2 * Copyright (C) 2003-2004 Jakub Jermar
[f761f1eb]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>
[0970f43]30#include <arch/mm/asid.h>
[f761f1eb]31#include <mm/tlb.h>
[1084a784]32#include <mm/page.h>
33#include <mm/vm.h>
[f761f1eb]34#include <arch/cp0.h>
35#include <panic.h>
36#include <arch.h>
[ab08b42]37#include <symtab.h>
[1084a784]38#include <synch/spinlock.h>
39#include <print.h>
[cc205f1]40#include <debug.h>
[9c0a9b3]41
[1084a784]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
[38a1a84]46static pte_t *find_mapping_and_check(__address badvaddr);
[cc205f1]47static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn);
[38a1a84]48
[1084a784]49/** Initialize TLB
50 *
51 * Initialize TLB.
52 * Invalidate all entries and mark wired entries.
53 */
[ce031f0]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++) {
[1084a784]67 cp0_index_write(i);
[ce031f0]68 tlbwi();
69 }
70
71 /*
72 * The kernel is going to make use of some wired
[1084a784]73 * entries (e.g. mapping kernel stacks in kseg3).
[ce031f0]74 */
75 cp0_wired_write(TLB_WIRED);
76}
77
[1084a784]78/** Process TLB Refill Exception
79 *
80 * Process TLB Refill Exception.
81 *
82 * @param pstate Interrupted register context.
83 */
[909c6e3]84void tlb_refill(struct exception_regdump *pstate)
[1084a784]85{
[cc205f1]86 entry_lo_t lo;
[1084a784]87 __address badvaddr;
88 pte_t *pte;
[fd3c9e5]89
90// debug
91 entry_hi_t hi;
92
[1084a784]93 badvaddr = cp0_badvaddr_read();
[fd3c9e5]94
95// debug
96 hi.value = cp0_entry_hi_read();
97 printf("TLB Refill: hi.vnp2=%X\n", hi.vpn2);
[1084a784]98
[38a1a84]99 spinlock_lock(&VM->lock);
100 pte = find_mapping_and_check(badvaddr);
[1084a784]101 if (!pte)
102 goto fail;
[38a1a84]103
[1084a784]104 /*
[38a1a84]105 * Record access to PTE.
[1084a784]106 */
[38a1a84]107 pte->a = 1;
108
109 prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
[1084a784]110
111 /*
112 * New entry is to be inserted into TLB
113 */
114 if ((badvaddr/PAGE_SIZE) % 2 == 0) {
[cc205f1]115 cp0_entry_lo0_write(lo.value);
[1084a784]116 cp0_entry_lo1_write(0);
117 }
118 else {
119 cp0_entry_lo0_write(0);
[cc205f1]120 cp0_entry_lo1_write(lo.value);
[1084a784]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
[38a1a84]132/** Process TLB Invalid Exception
133 *
134 * Process TLB Invalid Exception.
135 *
136 * @param pstate Interrupted register context.
137 */
[1084a784]138void tlb_invalid(struct exception_regdump *pstate)
139{
[cc205f1]140 tlb_index_t index;
[38a1a84]141 __address badvaddr;
[cc205f1]142 entry_lo_t lo;
[38a1a84]143 pte_t *pte;
144
145 badvaddr = cp0_badvaddr_read();
146
147 /*
148 * Locate the faulting entry in TLB.
149 */
150 tlbp();
[cc205f1]151 index.value = cp0_index_read();
[38a1a84]152
153 spinlock_lock(&VM->lock);
154
155 /*
156 * Fail if the entry is not in TLB.
157 */
[cc205f1]158 if (index.p) {
159 printf("TLB entry not found.\n");
[38a1a84]160 goto fail;
[cc205f1]161 }
[38a1a84]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)
[cc205f1]183 cp0_entry_lo0_write(lo.value);
[38a1a84]184 else
[cc205f1]185 cp0_entry_lo1_write(lo.value);
[38a1a84]186 tlbwi();
187
188 spinlock_unlock(&VM->lock);
189 return;
190
191fail:
192 spinlock_unlock(&VM->lock);
[1084a784]193 tlb_invalid_fail(pstate);
194}
195
[38a1a84]196/** Process TLB Modified Exception
197 *
198 * Process TLB Modified Exception.
199 *
200 * @param pstate Interrupted register context.
201 */
[1084a784]202void tlb_modified(struct exception_regdump *pstate)
203{
[cc205f1]204 tlb_index_t index;
[38a1a84]205 __address badvaddr;
[cc205f1]206 entry_lo_t lo;
[38a1a84]207 pte_t *pte;
208
209 badvaddr = cp0_badvaddr_read();
210
211 /*
212 * Locate the faulting entry in TLB.
213 */
214 tlbp();
[cc205f1]215 index.value = cp0_index_read();
[38a1a84]216
217 spinlock_lock(&VM->lock);
218
219 /*
220 * Fail if the entry is not in TLB.
221 */
[cc205f1]222 if (index.p) {
223 printf("TLB entry not found.\n");
[38a1a84]224 goto fail;
[cc205f1]225 }
[38a1a84]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)
[cc205f1]254 cp0_entry_lo0_write(lo.value);
[38a1a84]255 else
[cc205f1]256 cp0_entry_lo1_write(lo.value);
[38a1a84]257 tlbwi();
258
259 spinlock_unlock(&VM->lock);
260 return;
261
262fail:
263 spinlock_unlock(&VM->lock);
[1084a784]264 tlb_modified_fail(pstate);
265}
266
267void tlb_refill_fail(struct exception_regdump *pstate)
[f761f1eb]268{
[38de8a5]269 char *symbol = "";
270 char *sym2 = "";
271
[3156582]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;
[1084a784]278 panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
[f761f1eb]279}
280
[1084a784]281
282void tlb_invalid_fail(struct exception_regdump *pstate)
[f761f1eb]283{
[ab08b42]284 char *symbol = "";
285
[3156582]286 char *s = get_symtab_entry(pstate->epc);
287 if (s)
288 symbol = s;
[38a1a84]289 panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
[f761f1eb]290}
291
[1084a784]292void tlb_modified_fail(struct exception_regdump *pstate)
[ce031f0]293{
294 char *symbol = "";
295
296 char *s = get_symtab_entry(pstate->epc);
297 if (s)
298 symbol = s;
[38a1a84]299 panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
[ce031f0]300}
301
[cc205f1]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)
[f761f1eb]309{
[cc205f1]310 entry_hi_t hi;
[0970f43]311 pri_t pri;
[cc205f1]312 int i;
[0970f43]313
[cc205f1]314 ASSERT(asid != ASID_INVALID);
315
[0970f43]316 pri = cpu_priority_high();
317
[cc205f1]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 }
[0970f43]331
332 cpu_priority_restore(pri);
[f761f1eb]333}
[38a1a84]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{
[cc205f1]346 entry_hi_t hi;
[38a1a84]347 pte_t *pte;
348
[cc205f1]349 hi.value = cp0_entry_hi_read();
[38a1a84]350
351 /*
352 * Handler cannot succeed if the ASIDs don't match.
353 */
[cc205f1]354 if (hi.asid != VM->asid) {
355 printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
[38a1a84]356 return NULL;
[cc205f1]357 }
[38a1a84]358
359 /*
360 * Handler cannot succeed if badvaddr has no mapping.
361 */
362 pte = find_mapping(badvaddr, 0);
[cc205f1]363 if (!pte) {
364 printf("No such mapping.\n");
[38a1a84]365 return NULL;
[cc205f1]366 }
[38a1a84]367
368 /*
369 * Handler cannot succeed if the mapping is marked as invalid.
370 */
[cc205f1]371 if (!pte->v) {
372 printf("Invalid mapping.\n");
[38a1a84]373 return NULL;
[cc205f1]374 }
[38a1a84]375
376 return pte;
377}
378
[cc205f1]379void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
[38a1a84]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.