Subversion Repositories HelenOS-historic

Rev

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

Rev 391 Rev 394
Line 40... Line 40...
40
 
40
 
41
static void tlb_refill_fail(struct exception_regdump *pstate);
41
static void tlb_refill_fail(struct exception_regdump *pstate);
42
static void tlb_invalid_fail(struct exception_regdump *pstate);
42
static void tlb_invalid_fail(struct exception_regdump *pstate);
43
static void tlb_modified_fail(struct exception_regdump *pstate);
43
static void tlb_modified_fail(struct exception_regdump *pstate);
44
 
44
 
-
 
45
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, bool c, __address pfn);
-
 
47
 
45
/** Initialize TLB
48
/** Initialize TLB
46
 *
49
 *
47
 * Initialize TLB.
50
 * Initialize TLB.
48
 * Invalidate all entries and mark wired entries.
51
 * Invalidate all entries and mark wired entries.
49
 */
52
 */
Line 77... Line 80...
77
 *
80
 *
78
 * @param pstate Interrupted register context.
81
 * @param pstate Interrupted register context.
79
 */
82
 */
80
void tlb_refill(struct exception_regdump *pstate)
83
void tlb_refill(struct exception_regdump *pstate)
81
{
84
{
82
    struct entry_hi hi;
85
    struct entry_lo lo;
83
    __address badvaddr;
86
    __address badvaddr;
84
    pte_t *pte;
87
    pte_t *pte;
85
   
88
   
86
    *((__u32 *) &hi) = cp0_entry_hi_read();
-
 
87
    badvaddr = cp0_badvaddr_read();
89
    badvaddr = cp0_badvaddr_read();
88
   
90
   
89
    spinlock_lock(&VM->lock);
91
    spinlock_lock(&VM->lock);      
90
 
-
 
91
    /*
-
 
92
     * Refill cannot succeed if the ASIDs don't match.
-
 
93
     */
-
 
94
    if (hi.asid != VM->asid)
-
 
95
        goto fail;
-
 
96
 
-
 
97
    /*
-
 
98
     * Refill cannot succeed if badvaddr is not
-
 
99
     * associated with any mapping.
-
 
100
     */
-
 
101
    pte = find_mapping(badvaddr, 0);
92
    pte = find_mapping_and_check(badvaddr);
102
    if (!pte)
93
    if (!pte)
103
        goto fail;
94
        goto fail;
104
       
95
 
105
    /*
96
    /*
106
     * Refill cannot succeed if the mapping is marked as invalid.
97
     * Record access to PTE.
107
     */
98
     */
108
    if (!pte->v)
99
    pte->a = 1;
-
 
100
 
109
        goto fail;
101
    prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
110
 
102
 
111
    /*
103
    /*
112
     * New entry is to be inserted into TLB
104
     * New entry is to be inserted into TLB
113
     */
105
     */
114
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
-
 
115
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
106
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
116
        cp0_entry_lo0_write(*((__u32 *) pte));
107
        cp0_entry_lo0_write(*((__u32 *) &lo));
117
        cp0_entry_lo1_write(0);
108
        cp0_entry_lo1_write(0);
118
    }
109
    }
119
    else {
110
    else {
120
        cp0_entry_lo0_write(0);
111
        cp0_entry_lo0_write(0);
121
        cp0_entry_lo1_write(*((__u32 *) pte));
112
        cp0_entry_lo1_write(*((__u32 *) &lo));
122
    }
113
    }
123
    tlbwr();
114
    tlbwr();
124
 
115
 
125
    spinlock_unlock(&VM->lock);
116
    spinlock_unlock(&VM->lock);
126
    return;
117
    return;
Line 128... Line 119...
128
fail:
119
fail:
129
    spinlock_unlock(&VM->lock);
120
    spinlock_unlock(&VM->lock);
130
    tlb_refill_fail(pstate);
121
    tlb_refill_fail(pstate);
131
}
122
}
132
 
123
 
-
 
124
/** Process TLB Invalid Exception
-
 
125
 *
-
 
126
 * Process TLB Invalid Exception.
-
 
127
 *
-
 
128
 * @param pstate Interrupted register context.
-
 
129
 */
133
void tlb_invalid(struct exception_regdump *pstate)
130
void tlb_invalid(struct exception_regdump *pstate)
134
{
131
{
-
 
132
    struct index index;
-
 
133
    __address badvaddr;
-
 
134
    struct entry_lo lo;
-
 
135
    pte_t *pte;
-
 
136
 
-
 
137
    badvaddr = cp0_badvaddr_read();
-
 
138
 
-
 
139
    /*
-
 
140
     * Locate the faulting entry in TLB.
-
 
141
     */
-
 
142
    tlbp();
-
 
143
    *((__u32 *) &index) = cp0_index_read();
-
 
144
   
-
 
145
    spinlock_lock(&VM->lock);  
-
 
146
   
-
 
147
    /*
-
 
148
     * Fail if the entry is not in TLB.
-
 
149
     */
-
 
150
    if (index.p)
-
 
151
        goto fail;
-
 
152
 
-
 
153
    pte = find_mapping_and_check(badvaddr);
-
 
154
    if (!pte)
-
 
155
        goto fail;
-
 
156
 
-
 
157
    /*
-
 
158
     * Read the faulting TLB entry.
-
 
159
     */
-
 
160
    tlbr();
-
 
161
 
-
 
162
    /*
-
 
163
     * Record access to PTE.
-
 
164
     */
-
 
165
    pte->a = 1;
-
 
166
 
-
 
167
    prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
-
 
168
 
-
 
169
    /*
-
 
170
     * The entry is to be updated in TLB.
-
 
171
     */
-
 
172
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
-
 
173
        cp0_entry_lo0_write(*((__u32 *) &lo));
-
 
174
    else
-
 
175
        cp0_entry_lo1_write(*((__u32 *) &lo));
-
 
176
    tlbwi();
-
 
177
 
-
 
178
    spinlock_unlock(&VM->lock);
-
 
179
    return;
-
 
180
   
-
 
181
fail:
-
 
182
    spinlock_unlock(&VM->lock);
135
    tlb_invalid_fail(pstate);
183
    tlb_invalid_fail(pstate);
136
}
184
}
137
 
185
 
-
 
186
/** Process TLB Modified Exception
-
 
187
 *
-
 
188
 * Process TLB Modified Exception.
-
 
189
 *
-
 
190
 * @param pstate Interrupted register context.
-
 
191
 */
-
 
192
 
138
void tlb_modified(struct exception_regdump *pstate)
193
void tlb_modified(struct exception_regdump *pstate)
139
{
194
{
-
 
195
    struct index index;
-
 
196
    __address badvaddr;
-
 
197
    struct entry_lo lo;
-
 
198
    pte_t *pte;
-
 
199
 
-
 
200
    badvaddr = cp0_badvaddr_read();
-
 
201
 
-
 
202
    /*
-
 
203
     * Locate the faulting entry in TLB.
-
 
204
     */
-
 
205
    tlbp();
-
 
206
    *((__u32 *) &index) = cp0_index_read();
-
 
207
   
-
 
208
    spinlock_lock(&VM->lock);  
-
 
209
   
-
 
210
    /*
-
 
211
     * Fail if the entry is not in TLB.
-
 
212
     */
-
 
213
    if (index.p)
-
 
214
        goto fail;
-
 
215
 
-
 
216
    pte = find_mapping_and_check(badvaddr);
-
 
217
    if (!pte)
-
 
218
        goto fail;
-
 
219
 
-
 
220
    /*
-
 
221
     * Fail if the page is not writable.
-
 
222
     */
-
 
223
    if (!pte->w)
-
 
224
        goto fail;
-
 
225
 
-
 
226
    /*
-
 
227
     * Read the faulting TLB entry.
-
 
228
     */
-
 
229
    tlbr();
-
 
230
 
-
 
231
    /*
-
 
232
     * Record access and write to PTE.
-
 
233
     */
-
 
234
    pte->a = 1;
-
 
235
    pte->d = 1;
-
 
236
 
-
 
237
    prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
-
 
238
 
-
 
239
    /*
-
 
240
     * The entry is to be updated in TLB.
-
 
241
     */
-
 
242
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
-
 
243
        cp0_entry_lo0_write(*((__u32 *) &lo));
-
 
244
    else
-
 
245
        cp0_entry_lo1_write(*((__u32 *) &lo));
-
 
246
    tlbwi();
-
 
247
 
-
 
248
    spinlock_unlock(&VM->lock);
-
 
249
    return;
-
 
250
   
-
 
251
fail:
-
 
252
    spinlock_unlock(&VM->lock);
140
    tlb_modified_fail(pstate);
253
    tlb_modified_fail(pstate);
141
}
254
}
142
 
255
 
143
void tlb_refill_fail(struct exception_regdump *pstate)
256
void tlb_refill_fail(struct exception_regdump *pstate)
144
{
257
{
Line 160... Line 273...
160
    char *symbol = "";
273
    char *symbol = "";
161
 
274
 
162
    char *s = get_symtab_entry(pstate->epc);
275
    char *s = get_symtab_entry(pstate->epc);
163
    if (s)
276
    if (s)
164
        symbol = s;
277
        symbol = s;
165
    panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(),
278
    panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
166
          pstate->epc, symbol);
-
 
167
}
279
}
168
 
280
 
169
void tlb_modified_fail(struct exception_regdump *pstate)
281
void tlb_modified_fail(struct exception_regdump *pstate)
170
{
282
{
171
    char *symbol = "";
283
    char *symbol = "";
172
 
284
 
173
    char *s = get_symtab_entry(pstate->epc);
285
    char *s = get_symtab_entry(pstate->epc);
174
    if (s)
286
    if (s)
175
        symbol = s;
287
        symbol = s;
176
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(),
288
    panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
177
          pstate->epc, symbol);
-
 
178
}
289
}
179
 
290
 
180
 
291
 
181
void tlb_invalidate(int asid)
292
void tlb_invalidate(int asid)
182
{
293
{
Line 186... Line 297...
186
   
297
   
187
    // TODO
298
    // TODO
188
   
299
   
189
    cpu_priority_restore(pri);
300
    cpu_priority_restore(pri);
190
}
301
}
-
 
302
 
-
 
303
/** Try to find PTE for faulting address
-
 
304
 *
-
 
305
 * Try to find PTE for faulting address.
-
 
306
 * The VM->lock must be held on entry to this function.
-
 
307
 *
-
 
308
 * @param badvaddr Faulting virtual address.
-
 
309
 *
-
 
310
 * @return PTE on success, NULL otherwise.
-
 
311
 */
-
 
312
pte_t *find_mapping_and_check(__address badvaddr)
-
 
313
{
-
 
314
    struct entry_hi hi;
-
 
315
    pte_t *pte;
-
 
316
 
-
 
317
    *((__u32 *) &hi) = cp0_entry_hi_read();
-
 
318
 
-
 
319
    /*
-
 
320
     * Handler cannot succeed if the ASIDs don't match.
-
 
321
     */
-
 
322
    if (hi.asid != VM->asid)
-
 
323
        return NULL;
-
 
324
   
-
 
325
    /*
-
 
326
     * Handler cannot succeed if badvaddr has no mapping.
-
 
327
     */
-
 
328
    pte = find_mapping(badvaddr, 0);
-
 
329
    if (!pte)
-
 
330
        return NULL;
-
 
331
 
-
 
332
    /*
-
 
333
     * Handler cannot succeed if the mapping is marked as invalid.
-
 
334
     */
-
 
335
    if (!pte->v)
-
 
336
        return NULL;
-
 
337
 
-
 
338
    return pte;
-
 
339
}
-
 
340
 
-
 
341
void prepare_entry_lo(struct entry_lo *lo, bool g, bool v, bool d, bool c, __address pfn)
-
 
342
{
-
 
343
    lo->g = g;
-
 
344
    lo->v = v;
-
 
345
    lo->d = d;
-
 
346
    lo->c = c;
-
 
347
    lo->pfn = pfn;
-
 
348
    lo->zero = 0;
-
 
349
}