Subversion Repositories HelenOS

Rev

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

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