Changes in kernel/arch/mips32/src/mm/tlb.c [8fe2c9bd:1dbc43f] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/mips32/src/mm/tlb.c
r8fe2c9bd r1dbc43f 48 48 #include <symtab.h> 49 49 50 #define PFN_SHIFT 12 51 #define VPN_SHIFT 12 52 #define ADDR2VPN(a) ((a) >> VPN_SHIFT) 53 #define ADDR2VPN2(a) (ADDR2VPN((a)) >> 1) 54 #define VPN2ADDR(vpn) ((vpn) << VPN_SHIFT) 55 #define VPN22ADDR(vpn2) (VPN2ADDR(vpn2) << 1) 56 #define PFN2ADDR(pfn) ((pfn) << PFN_SHIFT) 57 58 #define BANK_SELECT_BIT(a) (((a) >> PAGE_WIDTH) & 1) 59 50 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *); 60 51 61 52 /** Initialize TLB. … … 93 84 { 94 85 entry_lo_t lo; 86 entry_hi_t hi; 87 asid_t asid; 95 88 uintptr_t badvaddr; 96 uintptr_t page;97 89 pte_t *pte; 98 90 99 91 badvaddr = cp0_badvaddr_read(); 100 page = ALIGN_DOWN(badvaddr, PAGE_SIZE);101 102 pte = page_mapping_find(AS, page, true);103 if (pte && pte->p) {92 asid = AS->asid; 93 94 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 95 if (pte) { 104 96 /* 105 97 * Record access to PTE. … … 107 99 pte->a = 1; 108 100 101 tlb_prepare_entry_hi(&hi, asid, badvaddr); 109 102 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, 110 103 pte->cacheable, pte->pfn); … … 113 106 * New entry is to be inserted into TLB 114 107 */ 115 if (BANK_SELECT_BIT(badvaddr) == 0) { 108 cp0_entry_hi_write(hi.value); 109 if ((badvaddr / PAGE_SIZE) % 2 == 0) { 116 110 cp0_entry_lo0_write(lo.value); 117 111 cp0_entry_lo1_write(0); … … 122 116 cp0_pagemask_write(TLB_PAGE_MASK_16K); 123 117 tlbwr(); 124 return; 125 } 126 127 (void) as_page_fault(page, PF_ACCESS_READ, istate); 118 } 128 119 } 129 120 … … 134 125 void tlb_invalid(istate_t *istate) 135 126 { 136 entry_lo_t lo;137 127 tlb_index_t index; 138 128 uintptr_t badvaddr; 139 uintptr_t page; 129 entry_lo_t lo; 130 entry_hi_t hi; 140 131 pte_t *pte; 132 133 badvaddr = cp0_badvaddr_read(); 141 134 142 135 /* 143 136 * Locate the faulting entry in TLB. 144 137 */ 138 hi.value = cp0_entry_hi_read(); 139 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr); 140 cp0_entry_hi_write(hi.value); 145 141 tlbp(); 146 142 index.value = cp0_index_read(); 147 143 148 #if defined(PROCESSOR_4Kc)149 /*150 * This can happen on a 4Kc when Status.EXL is 1 and there is a TLB miss.151 * EXL is 1 when interrupts are disabled. The combination of a TLB miss152 * and disabled interrupts is possible in copy_to/from_uspace().153 */154 if (index.p) {155 tlb_refill(istate);156 return;157 }158 #endif159 160 144 ASSERT(!index.p); 161 145 162 badvaddr = cp0_badvaddr_read(); 163 page = ALIGN_DOWN(badvaddr, PAGE_SIZE); 164 165 pte = page_mapping_find(AS, page, true); 166 if (pte && pte->p) { 146 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 147 if (pte) { 167 148 /* 168 149 * Read the faulting TLB entry. … … 181 162 * The entry is to be updated in TLB. 182 163 */ 183 if ( BANK_SELECT_BIT(badvaddr)== 0)164 if ((badvaddr / PAGE_SIZE) % 2 == 0) 184 165 cp0_entry_lo0_write(lo.value); 185 166 else 186 167 cp0_entry_lo1_write(lo.value); 168 cp0_pagemask_write(TLB_PAGE_MASK_16K); 187 169 tlbwi(); 188 return; 189 } 190 191 (void) as_page_fault(page, PF_ACCESS_READ, istate); 170 } 192 171 } 193 172 … … 198 177 void tlb_modified(istate_t *istate) 199 178 { 200 entry_lo_t lo;201 179 tlb_index_t index; 202 180 uintptr_t badvaddr; 203 uintptr_t page; 181 entry_lo_t lo; 182 entry_hi_t hi; 204 183 pte_t *pte; 205 184 206 185 badvaddr = cp0_badvaddr_read(); 207 page = ALIGN_DOWN(badvaddr, PAGE_SIZE);208 186 209 187 /* 210 188 * Locate the faulting entry in TLB. 211 189 */ 190 hi.value = cp0_entry_hi_read(); 191 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr); 192 cp0_entry_hi_write(hi.value); 212 193 tlbp(); 213 194 index.value = cp0_index_read(); 214 195 215 196 /* 216 * Emit warning if the entry is not in TLB. 217 * 218 * We do not assert on this because this could be a manifestation of 219 * an emulator bug, such as QEMU Bug #1128935: 220 * https://bugs.launchpad.net/qemu/+bug/1128935 197 * Fail if the entry is not in TLB. 221 198 */ 222 if (index.p) { 223 printf("%s: TLBP failed in exception handler (badvaddr=%#" 224 PRIxn ", ASID=%d).\n", __func__, badvaddr, 225 AS ? AS->asid : -1); 226 return; 227 } 228 229 pte = page_mapping_find(AS, page, true); 230 if (pte && pte->p && pte->w) { 199 ASSERT(!index.p); 200 201 pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate); 202 if (pte) { 231 203 /* 232 204 * Read the faulting TLB entry. … … 246 218 * The entry is to be updated in TLB. 247 219 */ 248 if ( BANK_SELECT_BIT(badvaddr)== 0)220 if ((badvaddr / PAGE_SIZE) % 2 == 0) 249 221 cp0_entry_lo0_write(lo.value); 250 222 else 251 223 cp0_entry_lo1_write(lo.value); 224 cp0_pagemask_write(TLB_PAGE_MASK_16K); 252 225 tlbwi(); 253 return; 254 } 255 256 (void) as_page_fault(page, PF_ACCESS_WRITE, istate); 226 } 227 } 228 229 /** Try to find PTE for faulting address. 230 * 231 * @param badvaddr Faulting virtual address. 232 * @param access Access mode that caused the fault. 233 * @param istate Pointer to interrupted state. 234 * 235 * @return PTE on success, NULL otherwise. 236 */ 237 pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate) 238 { 239 entry_hi_t hi; 240 pte_t *pte; 241 242 hi.value = cp0_entry_hi_read(); 243 244 ASSERT(hi.asid == AS->asid); 245 246 /* 247 * Check if the mapping exists in page tables. 248 */ 249 pte = page_mapping_find(AS, badvaddr, true); 250 if (pte && pte->p && (pte->w || access != PF_ACCESS_WRITE)) { 251 /* 252 * Mapping found in page tables. 253 * Immediately succeed. 254 */ 255 return pte; 256 } 257 258 /* 259 * Mapping not found in page tables. 260 * Resort to higher-level page fault handler. 261 */ 262 if (as_page_fault(badvaddr, access, istate) == AS_PF_OK) { 263 pte = page_mapping_find(AS, badvaddr, true); 264 ASSERT(pte && pte->p); 265 ASSERT(pte->w || access != PF_ACCESS_WRITE); 266 return pte; 267 } 268 269 return NULL; 257 270 } 258 271 … … 271 284 void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr) 272 285 { 273 hi->value = 0; 274 hi->vpn2 = ADDR2VPN2(ALIGN_DOWN(addr, PAGE_SIZE)); 286 hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2); 275 287 hi->asid = asid; 276 288 } … … 279 291 void tlb_print(void) 280 292 { 281 page_mask_t mask , mask_save;282 entry_lo_t lo0, lo 0_save, lo1, lo1_save;293 page_mask_t mask; 294 entry_lo_t lo0, lo1; 283 295 entry_hi_t hi, hi_save; 284 296 unsigned int i; 285 297 286 298 hi_save.value = cp0_entry_hi_read(); 287 lo0_save.value = cp0_entry_lo0_read(); 288 lo1_save.value = cp0_entry_lo1_read(); 289 mask_save.value = cp0_pagemask_read(); 290 291 printf("[nr] [asid] [vpn2 ] [mask] [gvdc] [pfn ]\n"); 299 300 printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n"); 292 301 293 302 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 300 309 lo1.value = cp0_entry_lo1_read(); 301 310 302 printf("%-4u %-6u % 0#10x %-#6x %1u%1u%1u%1u %0#10x\n",303 i, hi.asid, VPN22ADDR(hi.vpn2), mask.mask,304 lo0.g, lo0.v, lo0.d, lo0.c, PFN2ADDR(lo0.pfn));305 printf(" %1u%1u%1u%1u %0#10x\n",306 lo1.g, lo1.v, lo1.d, lo1.c, PFN2ADDR(lo1.pfn));311 printf("%-4u %-6u %#6x %#6x %1u%1u%1u%1u %#6x\n", 312 i, hi.asid, hi.vpn2, mask.mask, 313 lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn); 314 printf(" %1u%1u%1u%1u %#6x\n", 315 lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn); 307 316 } 308 317 309 318 cp0_entry_hi_write(hi_save.value); 310 cp0_entry_lo0_write(lo0_save.value);311 cp0_entry_lo1_write(lo1_save.value);312 cp0_pagemask_write(mask_save.value);313 319 } 314 320 … … 316 322 void tlb_invalidate_all(void) 317 323 { 324 ipl_t ipl; 318 325 entry_lo_t lo0, lo1; 319 326 entry_hi_t hi_save; 320 327 int i; 321 328 322 ASSERT(interrupts_disabled());323 324 329 hi_save.value = cp0_entry_hi_read(); 330 ipl = interrupts_disable(); 325 331 326 332 for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) { … … 340 346 } 341 347 348 interrupts_restore(ipl); 342 349 cp0_entry_hi_write(hi_save.value); 343 350 } … … 349 356 void tlb_invalidate_asid(asid_t asid) 350 357 { 358 ipl_t ipl; 351 359 entry_lo_t lo0, lo1; 352 360 entry_hi_t hi, hi_save; 353 361 int i; 354 362 355 ASSERT(interrupts_disabled());356 363 ASSERT(asid != ASID_INVALID); 357 364 358 365 hi_save.value = cp0_entry_hi_read(); 366 ipl = interrupts_disable(); 359 367 360 368 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 378 386 } 379 387 388 interrupts_restore(ipl); 380 389 cp0_entry_hi_write(hi_save.value); 381 390 } … … 391 400 { 392 401 unsigned int i; 402 ipl_t ipl; 393 403 entry_lo_t lo0, lo1; 394 404 entry_hi_t hi, hi_save; 395 405 tlb_index_t index; 396 397 ASSERT(interrupts_disabled());398 406 399 407 if (asid == ASID_INVALID) … … 401 409 402 410 hi_save.value = cp0_entry_hi_read(); 411 ipl = interrupts_disable(); 403 412 404 413 for (i = 0; i < cnt + 1; i += 2) { 414 hi.value = 0; 405 415 tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE); 406 416 cp0_entry_hi_write(hi.value); … … 429 439 } 430 440 441 interrupts_restore(ipl); 431 442 cp0_entry_hi_write(hi_save.value); 432 443 }
Note:
See TracChangeset
for help on using the changeset viewer.