Subversion Repositories HelenOS

Rev

Rev 598 | 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