Subversion Repositories HelenOS

Rev

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

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