Subversion Repositories HelenOS

Rev

Rev 594 | Rev 599 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 594 Rev 598
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
 
-
 
60
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
58
    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);
-
 
64
 
59
 
65
    /*
-
 
66
     * Invalidate all entries.
60
    tlb_invalidate_all();
67
     */
-
 
68
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
-
 
69
        cp0_index_write(i);
-
 
70
        tlbwi();
-
 
71
    }
61
       
72
   
-
 
73
    /*
62
    /*
74
     * The kernel is going to make use of some wired
63
     * The kernel is going to make use of some wired
75
     * entries (e.g. mapping kernel stacks in kseg3).
64
     * entries (e.g. mapping kernel stacks in kseg3).
76
     */
65
     */
77
    cp0_wired_write(TLB_WIRED);
66
    cp0_wired_write(TLB_WIRED);
78
}
67
}
79
 
68
 
80
/** Process TLB Refill Exception
69
/** Process TLB Refill Exception
81
 *
70
 *
82
 * Process TLB Refill Exception.
71
 * Process TLB Refill Exception.
83
 *
72
 *
84
 * @param pstate Interrupted register context.
73
 * @param pstate Interrupted register context.
85
 */
74
 */
86
void tlb_refill(struct exception_regdump *pstate)
75
void tlb_refill(struct exception_regdump *pstate)
87
{
76
{
88
    entry_lo_t lo;
77
    entry_lo_t lo;
89
    entry_hi_t hi; 
78
    entry_hi_t hi; 
90
    __address badvaddr;
79
    __address badvaddr;
91
    pte_t *pte;
80
    pte_t *pte;
92
 
81
 
93
    badvaddr = cp0_badvaddr_read();
82
    badvaddr = cp0_badvaddr_read();
94
 
83
 
95
    spinlock_lock(&VM->lock);      
84
    spinlock_lock(&VM->lock);      
96
 
85
 
97
    pte = find_mapping_and_check(badvaddr);
86
    pte = find_mapping_and_check(badvaddr);
98
    if (!pte)
87
    if (!pte)
99
        goto fail;
88
        goto fail;
100
 
89
 
101
    /*
90
    /*
102
     * Record access to PTE.
91
     * Record access to PTE.
103
     */
92
     */
104
    pte->a = 1;
93
    pte->a = 1;
105
 
94
 
106
    prepare_entry_hi(&hi, VM->asid, badvaddr);
95
    prepare_entry_hi(&hi, VM->asid, badvaddr);
107
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn);
96
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn);
108
 
97
 
109
    /*
98
    /*
110
     * New entry is to be inserted into TLB
99
     * New entry is to be inserted into TLB
111
     */
100
     */
112
    cp0_entry_hi_write(hi.value);
101
    cp0_entry_hi_write(hi.value);
113
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
102
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
114
        cp0_entry_lo0_write(lo.value);
103
        cp0_entry_lo0_write(lo.value);
115
        cp0_entry_lo1_write(0);
104
        cp0_entry_lo1_write(0);
116
    }
105
    }
117
    else {
106
    else {
118
        cp0_entry_lo0_write(0);
107
        cp0_entry_lo0_write(0);
119
        cp0_entry_lo1_write(lo.value);
108
        cp0_entry_lo1_write(lo.value);
120
    }
109
    }
121
    tlbwr();
110
    tlbwr();
122
 
111
 
123
    spinlock_unlock(&VM->lock);
112
    spinlock_unlock(&VM->lock);
124
    return;
113
    return;
125
   
114
   
126
fail:
115
fail:
127
    spinlock_unlock(&VM->lock);
116
    spinlock_unlock(&VM->lock);
128
    tlb_refill_fail(pstate);
117
    tlb_refill_fail(pstate);
129
}
118
}
130
 
119
 
131
/** Process TLB Invalid Exception
120
/** Process TLB Invalid Exception
132
 *
121
 *
133
 * Process TLB Invalid Exception.
122
 * Process TLB Invalid Exception.
134
 *
123
 *
135
 * @param pstate Interrupted register context.
124
 * @param pstate Interrupted register context.
136
 */
125
 */
137
void tlb_invalid(struct exception_regdump *pstate)
126
void tlb_invalid(struct exception_regdump *pstate)
138
{
127
{
139
    tlb_index_t index;
128
    tlb_index_t index;
140
    __address badvaddr;
129
    __address badvaddr;
141
    entry_lo_t lo;
130
    entry_lo_t lo;
142
    entry_hi_t hi;
131
    entry_hi_t hi;
143
    pte_t *pte;
132
    pte_t *pte;
144
 
133
 
145
    badvaddr = cp0_badvaddr_read();
134
    badvaddr = cp0_badvaddr_read();
146
 
135
 
147
    /*
136
    /*
148
     * Locate the faulting entry in TLB.
137
     * Locate the faulting entry in TLB.
149
     */
138
     */
150
    hi.value = cp0_entry_hi_read();
139
    hi.value = cp0_entry_hi_read();
151
    prepare_entry_hi(&hi, hi.asid, badvaddr);
140
    prepare_entry_hi(&hi, hi.asid, badvaddr);
152
    cp0_entry_hi_write(hi.value);
141
    cp0_entry_hi_write(hi.value);
153
    tlbp();
142
    tlbp();
154
    index.value = cp0_index_read();
143
    index.value = cp0_index_read();
155
   
144
   
156
    spinlock_lock(&VM->lock);  
145
    spinlock_lock(&VM->lock);  
157
   
146
   
158
    /*
147
    /*
159
     * Fail if the entry is not in TLB.
148
     * Fail if the entry is not in TLB.
160
     */
149
     */
161
    if (index.p) {
150
    if (index.p) {
162
        printf("TLB entry not found.\n");
151
        printf("TLB entry not found.\n");
163
        goto fail;
152
        goto fail;
164
    }
153
    }
165
 
154
 
166
    pte = find_mapping_and_check(badvaddr);
155
    pte = find_mapping_and_check(badvaddr);
167
    if (!pte)
156
    if (!pte)
168
        goto fail;
157
        goto fail;
169
 
158
 
170
    /*
159
    /*
171
     * Read the faulting TLB entry.
160
     * Read the faulting TLB entry.
172
     */
161
     */
173
    tlbr();
162
    tlbr();
174
 
163
 
175
    /*
164
    /*
176
     * Record access to PTE.
165
     * Record access to PTE.
177
     */
166
     */
178
    pte->a = 1;
167
    pte->a = 1;
179
 
168
 
180
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn);
169
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->lo.d, pte->lo.c, pte->lo.pfn);
181
 
170
 
182
    /*
171
    /*
183
     * The entry is to be updated in TLB.
172
     * The entry is to be updated in TLB.
184
     */
173
     */
185
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
174
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
186
        cp0_entry_lo0_write(lo.value);
175
        cp0_entry_lo0_write(lo.value);
187
    else
176
    else
188
        cp0_entry_lo1_write(lo.value);
177
        cp0_entry_lo1_write(lo.value);
189
    tlbwi();
178
    tlbwi();
190
 
179
 
191
    spinlock_unlock(&VM->lock);
180
    spinlock_unlock(&VM->lock);
192
    return;
181
    return;
193
   
182
   
194
fail:
183
fail:
195
    spinlock_unlock(&VM->lock);
184
    spinlock_unlock(&VM->lock);
196
    tlb_invalid_fail(pstate);
185
    tlb_invalid_fail(pstate);
197
}
186
}
198
 
187
 
199
/** Process TLB Modified Exception
188
/** Process TLB Modified Exception
200
 *
189
 *
201
 * Process TLB Modified Exception.
190
 * Process TLB Modified Exception.
202
 *
191
 *
203
 * @param pstate Interrupted register context.
192
 * @param pstate Interrupted register context.
204
 */
193
 */
205
void tlb_modified(struct exception_regdump *pstate)
194
void tlb_modified(struct exception_regdump *pstate)
206
{
195
{
207
    tlb_index_t index;
196
    tlb_index_t index;
208
    __address badvaddr;
197
    __address badvaddr;
209
    entry_lo_t lo;
198
    entry_lo_t lo;
210
    entry_hi_t hi;
199
    entry_hi_t hi;
211
    pte_t *pte;
200
    pte_t *pte;
212
 
201
 
213
    badvaddr = cp0_badvaddr_read();
202
    badvaddr = cp0_badvaddr_read();
214
 
203
 
215
    /*
204
    /*
216
     * Locate the faulting entry in TLB.
205
     * Locate the faulting entry in TLB.
217
     */
206
     */
218
    hi.value = cp0_entry_hi_read();
207
    hi.value = cp0_entry_hi_read();
219
    prepare_entry_hi(&hi, hi.asid, badvaddr);
208
    prepare_entry_hi(&hi, hi.asid, badvaddr);
220
    cp0_entry_hi_write(hi.value);
209
    cp0_entry_hi_write(hi.value);
221
    tlbp();
210
    tlbp();
222
    index.value = cp0_index_read();
211
    index.value = cp0_index_read();
223
   
212
   
224
    spinlock_lock(&VM->lock);  
213
    spinlock_lock(&VM->lock);  
225
   
214
   
226
    /*
215
    /*
227
     * Fail if the entry is not in TLB.
216
     * Fail if the entry is not in TLB.
228
     */
217
     */
229
    if (index.p) {
218
    if (index.p) {
230
        printf("TLB entry not found.\n");
219
        printf("TLB entry not found.\n");
231
        goto fail;
220
        goto fail;
232
    }
221
    }
233
 
222
 
234
    pte = find_mapping_and_check(badvaddr);
223
    pte = find_mapping_and_check(badvaddr);
235
    if (!pte)
224
    if (!pte)
236
        goto fail;
225
        goto fail;
237
 
226
 
238
    /*
227
    /*
239
     * Fail if the page is not writable.
228
     * Fail if the page is not writable.
240
     */
229
     */
241
    if (!pte->w)
230
    if (!pte->w)
242
        goto fail;
231
        goto fail;
243
 
232
 
244
    /*
233
    /*
245
     * Read the faulting TLB entry.
234
     * Read the faulting TLB entry.
246
     */
235
     */
247
    tlbr();
236
    tlbr();
248
 
237
 
249
    /*
238
    /*
250
     * Record access and write to PTE.
239
     * Record access and write to PTE.
251
     */
240
     */
252
    pte->a = 1;
241
    pte->a = 1;
253
    pte->lo.d = 1;
242
    pte->lo.d = 1;
254
 
243
 
255
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->w, pte->lo.c, pte->lo.pfn);
244
    prepare_entry_lo(&lo, pte->lo.g, pte->lo.v, pte->w, pte->lo.c, pte->lo.pfn);
256
 
245
 
257
    /*
246
    /*
258
     * The entry is to be updated in TLB.
247
     * The entry is to be updated in TLB.
259
     */
248
     */
260
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
249
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
261
        cp0_entry_lo0_write(lo.value);
250
        cp0_entry_lo0_write(lo.value);
262
    else
251
    else
263
        cp0_entry_lo1_write(lo.value);
252
        cp0_entry_lo1_write(lo.value);
264
    tlbwi();
253
    tlbwi();
265
 
254
 
266
    spinlock_unlock(&VM->lock);
255
    spinlock_unlock(&VM->lock);
267
    return;
256
    return;
268
   
257
   
269
fail:
258
fail:
270
    spinlock_unlock(&VM->lock);
259
    spinlock_unlock(&VM->lock);
271
    tlb_modified_fail(pstate);
260
    tlb_modified_fail(pstate);
272
}
261
}
273
 
262
 
274
void tlb_refill_fail(struct exception_regdump *pstate)
263
void tlb_refill_fail(struct exception_regdump *pstate)
275
{
264
{
276
    char *symbol = "";
265
    char *symbol = "";
277
    char *sym2 = "";
266
    char *sym2 = "";
278
 
267
 
279
    char *s = get_symtab_entry(pstate->epc);
268
    char *s = get_symtab_entry(pstate->epc);
280
    if (s)
269
    if (s)
281
        symbol = s;
270
        symbol = s;
282
    s = get_symtab_entry(pstate->ra);
271
    s = get_symtab_entry(pstate->ra);
283
    if (s)
272
    if (s)
284
        sym2 = s;
273
        sym2 = s;
285
    panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
274
    panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
286
}
275
}
287
 
276
 
288
 
277
 
289
void tlb_invalid_fail(struct exception_regdump *pstate)
278
void tlb_invalid_fail(struct exception_regdump *pstate)
290
{
279
{
291
    char *symbol = "";
280
    char *symbol = "";
292
 
281
 
293
    char *s = get_symtab_entry(pstate->epc);
282
    char *s = get_symtab_entry(pstate->epc);
294
    if (s)
283
    if (s)
295
        symbol = s;
284
        symbol = s;
296
    panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
285
    panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
297
}
286
}
298
 
287
 
299
void tlb_modified_fail(struct exception_regdump *pstate)
288
void tlb_modified_fail(struct exception_regdump *pstate)
300
{
289
{
301
    char *symbol = "";
290
    char *symbol = "";
302
 
291
 
303
    char *s = get_symtab_entry(pstate->epc);
292
    char *s = get_symtab_entry(pstate->epc);
304
    if (s)
293
    if (s)
305
        symbol = s;
294
        symbol = s;
306
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
295
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
307
}
296
}
308
 
297
 
309
/** Invalidate TLB entries with specified ASID
298
/** Invalidate TLB entries with specified ASID
310
 *
299
 *
311
 * Invalidate TLB entries with specified ASID.
300
 * Invalidate TLB entries with specified ASID.
312
 *
301
 *
313
 * @param asid ASID.
302
 * @param asid ASID.
314
 */
303
 */
315
void tlb_invalidate(asid_t asid)
304
void tlb_invalidate(asid_t asid)
316
{
305
{
317
    entry_hi_t hi;
306
    entry_hi_t hi;
318
    ipl_t ipl;
307
    ipl_t ipl;
319
    int i; 
308
    int i; 
320
   
309
   
321
    ASSERT(asid != ASID_INVALID);
310
    ASSERT(asid != ASID_INVALID);
322
 
311
 
323
    ipl = interrupts_disable();
312
    ipl = interrupts_disable();
324
   
313
   
325
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
314
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
326
        cp0_index_write(i);
315
        cp0_index_write(i);
327
        tlbr();
316
        tlbr();
328
       
317
       
329
        hi.value = cp0_entry_hi_read();
318
        hi.value = cp0_entry_hi_read();
330
        if (hi.asid == asid) {
319
        if (hi.asid == asid) {
331
            cp0_pagemask_write(TLB_PAGE_MASK_16K);
320
            cp0_pagemask_write(TLB_PAGE_MASK_16K);
332
            cp0_entry_hi_write(0);
321
            cp0_entry_hi_write(0);
333
            cp0_entry_lo0_write(0);
322
            cp0_entry_lo0_write(0);
334
            cp0_entry_lo1_write(0);
323
            cp0_entry_lo1_write(0);
335
            tlbwi();
324
            tlbwi();
336
        }
325
        }
337
    }
326
    }
338
   
327
   
339
    interrupts_restore(ipl);
328
    interrupts_restore(ipl);
340
}
329
}
341
 
330
 
342
/** Try to find PTE for faulting address
331
/** Try to find PTE for faulting address
343
 *
332
 *
344
 * Try to find PTE for faulting address.
333
 * Try to find PTE for faulting address.
345
 * The VM->lock must be held on entry to this function.
334
 * The VM->lock must be held on entry to this function.
346
 *
335
 *
347
 * @param badvaddr Faulting virtual address.
336
 * @param badvaddr Faulting virtual address.
348
 *
337
 *
349
 * @return PTE on success, NULL otherwise.
338
 * @return PTE on success, NULL otherwise.
350
 */
339
 */
351
pte_t *find_mapping_and_check(__address badvaddr)
340
pte_t *find_mapping_and_check(__address badvaddr)
352
{
341
{
353
    entry_hi_t hi;
342
    entry_hi_t hi;
354
    pte_t *pte;
343
    pte_t *pte;
355
 
344
 
356
    hi.value = cp0_entry_hi_read();
345
    hi.value = cp0_entry_hi_read();
357
 
346
 
358
    /*
347
    /*
359
     * Handler cannot succeed if the ASIDs don't match.
348
     * Handler cannot succeed if the ASIDs don't match.
360
     */
349
     */
361
    if (hi.asid != VM->asid) {
350
    if (hi.asid != VM->asid) {
362
        printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
351
        printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
363
        return NULL;
352
        return NULL;
364
    }
353
    }
365
   
354
   
366
    /*
355
    /*
367
     * Handler cannot succeed if badvaddr has no mapping.
356
     * Handler cannot succeed if badvaddr has no mapping.
368
     */
357
     */
369
    pte = page_mapping_find(badvaddr, 0);
358
    pte = page_mapping_find(badvaddr, 0);
370
    if (!pte) {
359
    if (!pte) {
371
        printf("No such mapping.\n");
360
        printf("No such mapping.\n");
372
        return NULL;
361
        return NULL;
373
    }
362
    }
374
 
363
 
375
    /*
364
    /*
376
     * Handler cannot succeed if the mapping is marked as invalid.
365
     * Handler cannot succeed if the mapping is marked as invalid.
377
     */
366
     */
378
    if (!pte->lo.v) {
367
    if (!pte->lo.v) {
379
        printf("Invalid mapping.\n");
368
        printf("Invalid mapping.\n");
380
        return NULL;
369
        return NULL;
381
    }
370
    }
382
 
371
 
383
    return pte;
372
    return pte;
384
}
373
}
385
 
374
 
386
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
375
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
387
{
376
{
388
    lo->value = 0;
377
    lo->value = 0;
389
    lo->g = g;
378
    lo->g = g;
390
    lo->v = v;
379
    lo->v = v;
391
    lo->d = d;
380
    lo->d = d;
392
    lo->c = c;
381
    lo->c = c;
393
    lo->pfn = pfn;
382
    lo->pfn = pfn;
394
}
383
}
395
 
384
 
396
void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr)
385
void prepare_entry_hi(entry_hi_t *hi, asid_t asid, __address addr)
397
{
386
{
398
    hi->value = (((addr/PAGE_SIZE)/2)*PAGE_SIZE*2);
387
    hi->value = (((addr/PAGE_SIZE)/2)*PAGE_SIZE*2);
399
    hi->asid = asid;
388
    hi->asid = asid;
400
}
389
}
401
 
390
 
402
/** Print contents of TLB. */
391
/** Print contents of TLB. */
403
void tlb_print(void)
392
void tlb_print(void)
404
{
393
{
405
    entry_lo_t lo0, lo1;
394
    entry_lo_t lo0, lo1;
406
    entry_hi_t hi;
395
    entry_hi_t hi;
407
    int i;
396
    int i;
408
 
397
 
409
    printf("TLB:\n");
398
    printf("TLB:\n");
410
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
399
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
411
        cp0_index_write(i);
400
        cp0_index_write(i);
412
 
-
 
413
        tlbr();
401
        tlbr();
414
       
402
       
415
        hi.value = cp0_entry_hi_read();
403
        hi.value = cp0_entry_hi_read();
416
        lo0.value = cp0_entry_lo0_read();
404
        lo0.value = cp0_entry_lo0_read();
417
        lo1.value = cp0_entry_lo1_read();
405
        lo1.value = cp0_entry_lo1_read();
418
       
406
       
419
        printf("%d: asid=%d, vpn2=%d\tg[0]=%d, v[0]=%d, d[0]=%d, c[0]=%B, pfn[0]=%d\n"
407
        printf("%d: asid=%d, vpn2=%d\tg[0]=%d, v[0]=%d, d[0]=%d, c[0]=%B, pfn[0]=%d\n"
420
               "\t\t\tg[1]=%d, v[1]=%d, d[1]=%d, c[1]=%B, pfn[1]=%d\n",
408
               "\t\t\tg[1]=%d, v[1]=%d, d[1]=%d, c[1]=%B, pfn[1]=%d\n",
421
               i, hi.asid, hi.vpn2, lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn,
409
               i, hi.asid, hi.vpn2, lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn,
422
               lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn);
410
               lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn);
423
    }
411
    }
-
 
412
}
-
 
413
 
-
 
414
/** Invalidate all TLB entries. */
-
 
415
void tlb_invalidate_all(void)
-
 
416
{
-
 
417
    int i;
-
 
418
 
-
 
419
    cp0_entry_hi_write(0);
-
 
420
    cp0_entry_lo0_write(0);
-
 
421
    cp0_entry_lo1_write(0);
-
 
422
 
-
 
423
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
-
 
424
        cp0_index_write(i);
-
 
425
        tlbwi();
-
 
426
    }
-
 
427
}
-
 
428
 
-
 
429
/** Invalidate all TLB entries belonging to specified address space.
-
 
430
 *
-
 
431
 * @param asid Address space identifier.
-
 
432
 */
-
 
433
void tlb_invalidate_asid(asid_t asid)
-
 
434
{
-
 
435
    entry_hi_t hi;
-
 
436
    int i;
-
 
437
 
-
 
438
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
-
 
439
        cp0_index_write(i);
-
 
440
        tlbr();
-
 
441
       
-
 
442
        if (hi.asid == asid) {
-
 
443
            cp0_entry_lo0_write(0);
-
 
444
            cp0_entry_lo1_write(0);
-
 
445
            tlbwi();
-
 
446
        }
-
 
447
    }
-
 
448
 
-
 
449
}
-
 
450
 
-
 
451
/** Invalidate TLB entry for specified page belonging to specified address space.
-
 
452
 *
-
 
453
 * @param asid Address space identifier.
-
 
454
 * @param page Page whose TLB entry is to be invalidated.
-
 
455
 */
-
 
456
void tlb_invalidate_page(asid_t asid, __address page)
-
 
457
{
-
 
458
    entry_hi_t hi;
-
 
459
    tlb_index_t index;
-
 
460
    int i;
-
 
461
 
-
 
462
    hi.value = 0;
-
 
463
    prepare_entry_hi(&hi, asid, page);
-
 
464
   
-
 
465
    tlbp();
-
 
466
    index.value = cp0_index_read();
-
 
467
 
-
 
468
    if (!index.p) {
-
 
469
        /* Entry was found, index register contains valid index. */
-
 
470
        cp0_entry_lo0_write(0);
-
 
471
        cp0_entry_lo1_write(0);
-
 
472
        tlbwi();
-
 
473
    }
424
}
474
}
425
 
475