Subversion Repositories HelenOS-historic

Rev

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

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