Subversion Repositories HelenOS-historic

Rev

Rev 395 | Rev 397 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 395 Rev 396
Line 35... Line 35...
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
 
41
 
41
static void tlb_refill_fail(struct exception_regdump *pstate);
42
static void tlb_refill_fail(struct exception_regdump *pstate);
42
static void tlb_invalid_fail(struct exception_regdump *pstate);
43
static void tlb_invalid_fail(struct exception_regdump *pstate);
43
static void tlb_modified_fail(struct exception_regdump *pstate);
44
static void tlb_modified_fail(struct exception_regdump *pstate);
44
 
45
 
45
static pte_t *find_mapping_and_check(__address badvaddr);
46
static pte_t *find_mapping_and_check(__address badvaddr);
46
static void prepare_entry_lo(struct entry_lo *lo, bool g, bool v, bool d, int c, __address pfn);
47
static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn);
47
 
48
 
48
/** Initialize TLB
49
/** Initialize TLB
49
 *
50
 *
50
 * Initialize TLB.
51
 * Initialize TLB.
51
 * Invalidate all entries and mark wired entries.
52
 * Invalidate all entries and mark wired entries.
Line 80... Line 81...
80
 *
81
 *
81
 * @param pstate Interrupted register context.
82
 * @param pstate Interrupted register context.
82
 */
83
 */
83
void tlb_refill(struct exception_regdump *pstate)
84
void tlb_refill(struct exception_regdump *pstate)
84
{
85
{
85
    struct entry_lo lo;
86
    entry_lo_t lo;
86
    __address badvaddr;
87
    __address badvaddr;
87
    pte_t *pte;
88
    pte_t *pte;
88
   
89
   
89
    badvaddr = cp0_badvaddr_read();
90
    badvaddr = cp0_badvaddr_read();
90
   
91
   
Line 102... Line 103...
102
 
103
 
103
    /*
104
    /*
104
     * New entry is to be inserted into TLB
105
     * New entry is to be inserted into TLB
105
     */
106
     */
106
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
107
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
107
        cp0_entry_lo0_write(*((__u32 *) &lo));
108
        cp0_entry_lo0_write(lo.value);
108
        cp0_entry_lo1_write(0);
109
        cp0_entry_lo1_write(0);
109
    }
110
    }
110
    else {
111
    else {
111
        cp0_entry_lo0_write(0);
112
        cp0_entry_lo0_write(0);
112
        cp0_entry_lo1_write(*((__u32 *) &lo));
113
        cp0_entry_lo1_write(lo.value);
113
    }
114
    }
114
    tlbwr();
115
    tlbwr();
115
 
116
 
116
    spinlock_unlock(&VM->lock);
117
    spinlock_unlock(&VM->lock);
117
    return;
118
    return;
Line 127... Line 128...
127
 *
128
 *
128
 * @param pstate Interrupted register context.
129
 * @param pstate Interrupted register context.
129
 */
130
 */
130
void tlb_invalid(struct exception_regdump *pstate)
131
void tlb_invalid(struct exception_regdump *pstate)
131
{
132
{
132
    struct index index;
133
    tlb_index_t index;
133
    __address badvaddr;
134
    __address badvaddr;
134
    struct entry_lo lo;
135
    entry_lo_t lo;
135
    pte_t *pte;
136
    pte_t *pte;
136
 
137
 
137
    badvaddr = cp0_badvaddr_read();
138
    badvaddr = cp0_badvaddr_read();
138
 
139
 
139
    /*
140
    /*
140
     * Locate the faulting entry in TLB.
141
     * Locate the faulting entry in TLB.
141
     */
142
     */
142
    tlbp();
143
    tlbp();
143
    *((__u32 *) &index) = cp0_index_read();
144
    index.value = cp0_index_read();
144
   
145
   
145
    spinlock_lock(&VM->lock);  
146
    spinlock_lock(&VM->lock);  
146
   
147
   
147
    /*
148
    /*
148
     * Fail if the entry is not in TLB.
149
     * Fail if the entry is not in TLB.
149
     */
150
     */
150
    if (index.p)
151
    if (index.p) {
-
 
152
        printf("TLB entry not found.\n");
151
        goto fail;
153
        goto fail;
-
 
154
    }
152
 
155
 
153
    pte = find_mapping_and_check(badvaddr);
156
    pte = find_mapping_and_check(badvaddr);
154
    if (!pte)
157
    if (!pte)
155
        goto fail;
158
        goto fail;
156
 
159
 
Line 168... Line 171...
168
 
171
 
169
    /*
172
    /*
170
     * The entry is to be updated in TLB.
173
     * The entry is to be updated in TLB.
171
     */
174
     */
172
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
175
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
173
        cp0_entry_lo0_write(*((__u32 *) &lo));
176
        cp0_entry_lo0_write(lo.value);
174
    else
177
    else
175
        cp0_entry_lo1_write(*((__u32 *) &lo));
178
        cp0_entry_lo1_write(lo.value);
176
    tlbwi();
179
    tlbwi();
177
 
180
 
178
    spinlock_unlock(&VM->lock);
181
    spinlock_unlock(&VM->lock);
179
    return;
182
    return;
180
   
183
   
Line 187... Line 190...
187
 *
190
 *
188
 * Process TLB Modified Exception.
191
 * Process TLB Modified Exception.
189
 *
192
 *
190
 * @param pstate Interrupted register context.
193
 * @param pstate Interrupted register context.
191
 */
194
 */
192
 
-
 
193
void tlb_modified(struct exception_regdump *pstate)
195
void tlb_modified(struct exception_regdump *pstate)
194
{
196
{
195
    struct index index;
197
    tlb_index_t index;
196
    __address badvaddr;
198
    __address badvaddr;
197
    struct entry_lo lo;
199
    entry_lo_t lo;
198
    pte_t *pte;
200
    pte_t *pte;
199
 
201
 
200
    badvaddr = cp0_badvaddr_read();
202
    badvaddr = cp0_badvaddr_read();
201
 
203
 
202
    /*
204
    /*
203
     * Locate the faulting entry in TLB.
205
     * Locate the faulting entry in TLB.
204
     */
206
     */
205
    tlbp();
207
    tlbp();
206
    *((__u32 *) &index) = cp0_index_read();
208
    index.value = cp0_index_read();
207
   
209
   
208
    spinlock_lock(&VM->lock);  
210
    spinlock_lock(&VM->lock);  
209
   
211
   
210
    /*
212
    /*
211
     * Fail if the entry is not in TLB.
213
     * Fail if the entry is not in TLB.
212
     */
214
     */
213
    if (index.p)
215
    if (index.p) {
-
 
216
        printf("TLB entry not found.\n");
214
        goto fail;
217
        goto fail;
-
 
218
    }
215
 
219
 
216
    pte = find_mapping_and_check(badvaddr);
220
    pte = find_mapping_and_check(badvaddr);
217
    if (!pte)
221
    if (!pte)
218
        goto fail;
222
        goto fail;
219
 
223
 
Line 238... Line 242...
238
 
242
 
239
    /*
243
    /*
240
     * The entry is to be updated in TLB.
244
     * The entry is to be updated in TLB.
241
     */
245
     */
242
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
246
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
243
        cp0_entry_lo0_write(*((__u32 *) &lo));
247
        cp0_entry_lo0_write(lo.value);
244
    else
248
    else
245
        cp0_entry_lo1_write(*((__u32 *) &lo));
249
        cp0_entry_lo1_write(lo.value);
246
    tlbwi();
250
    tlbwi();
247
 
251
 
248
    spinlock_unlock(&VM->lock);
252
    spinlock_unlock(&VM->lock);
249
    return;
253
    return;
250
   
254
   
Line 286... Line 290...
286
    if (s)
290
    if (s)
287
        symbol = s;
291
        symbol = s;
288
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
292
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
289
}
293
}
290
 
294
 
-
 
295
/** Invalidate TLB entries with specified ASID
-
 
296
 *
-
 
297
 * Invalidate TLB entries with specified ASID.
291
 
298
 *
-
 
299
 * @param asid ASID.
-
 
300
 */
292
void tlb_invalidate(int asid)
301
void tlb_invalidate(asid_t asid)
293
{
302
{
-
 
303
    entry_hi_t hi;
294
    pri_t pri;
304
    pri_t pri;
-
 
305
    int i; 
295
   
306
   
-
 
307
    ASSERT(asid != ASID_INVALID);
-
 
308
 
296
    pri = cpu_priority_high();
309
    pri = cpu_priority_high();
297
   
310
   
-
 
311
    for (i = 0; i < TLB_SIZE; i++) {
-
 
312
        cp0_index_write(i);
298
    // TODO
313
        tlbr();
-
 
314
       
-
 
315
        hi.value = cp0_entry_hi_read();
-
 
316
        if (hi.asid == asid) {
-
 
317
            cp0_pagemask_write(TLB_PAGE_MASK_16K);
-
 
318
            cp0_entry_hi_write(0);
-
 
319
            cp0_entry_lo0_write(0);
-
 
320
            cp0_entry_lo1_write(0);
-
 
321
            tlbwi();
-
 
322
        }
-
 
323
    }
299
   
324
   
300
    cpu_priority_restore(pri);
325
    cpu_priority_restore(pri);
301
}
326
}
302
 
327
 
303
/** Try to find PTE for faulting address
328
/** Try to find PTE for faulting address
Line 309... Line 334...
309
 *
334
 *
310
 * @return PTE on success, NULL otherwise.
335
 * @return PTE on success, NULL otherwise.
311
 */
336
 */
312
pte_t *find_mapping_and_check(__address badvaddr)
337
pte_t *find_mapping_and_check(__address badvaddr)
313
{
338
{
314
    struct entry_hi hi;
339
    entry_hi_t hi;
315
    pte_t *pte;
340
    pte_t *pte;
316
 
341
 
317
    *((__u32 *) &hi) = cp0_entry_hi_read();
342
    hi.value = cp0_entry_hi_read();
318
 
343
 
319
    /*
344
    /*
320
     * Handler cannot succeed if the ASIDs don't match.
345
     * Handler cannot succeed if the ASIDs don't match.
321
     */
346
     */
322
    if (hi.asid != VM->asid)
347
    if (hi.asid != VM->asid) {
-
 
348
        printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
323
        return NULL;
349
        return NULL;
-
 
350
    }
324
   
351
   
325
    /*
352
    /*
326
     * Handler cannot succeed if badvaddr has no mapping.
353
     * Handler cannot succeed if badvaddr has no mapping.
327
     */
354
     */
328
    pte = find_mapping(badvaddr, 0);
355
    pte = find_mapping(badvaddr, 0);
329
    if (!pte)
356
    if (!pte) {
-
 
357
        printf("No such mapping.\n");
330
        return NULL;
358
        return NULL;
-
 
359
    }
331
 
360
 
332
    /*
361
    /*
333
     * Handler cannot succeed if the mapping is marked as invalid.
362
     * Handler cannot succeed if the mapping is marked as invalid.
334
     */
363
     */
335
    if (!pte->v)
364
    if (!pte->v) {
-
 
365
        printf("Invalid mapping.\n");
336
        return NULL;
366
        return NULL;
-
 
367
    }
337
 
368
 
338
    return pte;
369
    return pte;
339
}
370
}
340
 
371
 
341
void prepare_entry_lo(struct entry_lo *lo, bool g, bool v, bool d, int c, __address pfn)
372
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
342
{
373
{
343
    lo->g = g;
374
    lo->g = g;
344
    lo->v = v;
375
    lo->v = v;
345
    lo->d = d;
376
    lo->d = d;
346
    lo->c = c;
377
    lo->c = c;