Rev 983 | Rev 1196 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 983 | Rev 1044 | ||
|---|---|---|---|
| Line 85... | Line 85... | ||
| 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 | */ |
| Line 120... | Line 125... | ||
| 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 | * |
| Line 152... | Line 157... | ||
| 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) { |
| Line 189... | Line 194... | ||
| 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 | * |
| Line 221... | Line 226... | ||
| 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) { |
| Line 265... | Line 270... | ||
| 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 | { |
| Line 347... | Line 352... | ||
| 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; |