Changes in kernel/arch/mips32/src/mm/tlb.c [1dbc43f:b2fa1204] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/mips32/src/mm/tlb.c
r1dbc43f rb2fa1204 43 43 #include <synch/mutex.h> 44 44 #include <print.h> 45 #include <log.h> 45 46 #include <debug.h> 46 47 #include <align.h> … … 48 49 #include <symtab.h> 49 50 50 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *); 51 #define PFN_SHIFT 12 52 #define VPN_SHIFT 12 53 54 #define ADDR2HI_VPN(a) ((a) >> VPN_SHIFT) 55 #define ADDR2HI_VPN2(a) (ADDR2HI_VPN((a)) >> 1) 56 57 #define HI_VPN2ADDR(vpn) ((vpn) << VPN_SHIFT) 58 #define HI_VPN22ADDR(vpn2) (HI_VPN2ADDR(vpn2) << 1) 59 60 #define LO_PFN2ADDR(pfn) ((pfn) << PFN_SHIFT) 61 62 #define BANK_SELECT_BIT(a) (((a) >> PAGE_WIDTH) & 1) 51 63 52 64 /** Initialize TLB. … … 84 96 { 85 97 entry_lo_t lo; 86 entry_hi_t hi;87 asid_t asid;88 98 uintptr_t badvaddr; 89 99 pte_t *pte; 90 100 91 101 badvaddr = cp0_badvaddr_read(); 92 asid = AS->asid; 93 94 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 95 if (pte) { 102 103 pte = page_mapping_find(AS, badvaddr, true); 104 if (pte && pte->p) { 96 105 /* 97 106 * Record access to PTE. … … 99 108 pte->a = 1; 100 109 101 tlb_prepare_entry_hi(&hi, asid, badvaddr);102 110 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, 103 111 pte->cacheable, pte->pfn); … … 106 114 * New entry is to be inserted into TLB 107 115 */ 108 cp0_entry_hi_write(hi.value); 109 if ((badvaddr / PAGE_SIZE) % 2 == 0) { 116 if (BANK_SELECT_BIT(badvaddr) == 0) { 110 117 cp0_entry_lo0_write(lo.value); 111 118 cp0_entry_lo1_write(0); … … 116 123 cp0_pagemask_write(TLB_PAGE_MASK_16K); 117 124 tlbwr(); 118 } 125 return; 126 } 127 128 (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate); 119 129 } 120 130 … … 125 135 void tlb_invalid(istate_t *istate) 126 136 { 137 entry_lo_t lo; 127 138 tlb_index_t index; 128 139 uintptr_t badvaddr; 129 entry_lo_t lo;130 entry_hi_t hi;131 140 pte_t *pte; 132 133 badvaddr = cp0_badvaddr_read();134 141 135 142 /* 136 143 * Locate the faulting entry in TLB. 137 144 */ 138 hi.value = cp0_entry_hi_read();139 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);140 cp0_entry_hi_write(hi.value);141 145 tlbp(); 142 146 index.value = cp0_index_read(); 143 147 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 miss 152 * and disabled interrupts is possible in copy_to/from_uspace(). 153 */ 154 if (index.p) { 155 tlb_refill(istate); 156 return; 157 } 158 #endif 159 144 160 ASSERT(!index.p); 145 161 146 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 147 if (pte) { 162 badvaddr = cp0_badvaddr_read(); 163 164 pte = page_mapping_find(AS, badvaddr, true); 165 if (pte && pte->p) { 148 166 /* 149 167 * Read the faulting TLB entry. … … 162 180 * The entry is to be updated in TLB. 163 181 */ 164 if ( (badvaddr / PAGE_SIZE) % 2== 0)182 if (BANK_SELECT_BIT(badvaddr) == 0) 165 183 cp0_entry_lo0_write(lo.value); 166 184 else 167 185 cp0_entry_lo1_write(lo.value); 168 cp0_pagemask_write(TLB_PAGE_MASK_16K);169 186 tlbwi(); 170 } 187 return; 188 } 189 190 (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate); 171 191 } 172 192 … … 177 197 void tlb_modified(istate_t *istate) 178 198 { 199 entry_lo_t lo; 179 200 tlb_index_t index; 180 201 uintptr_t badvaddr; 181 entry_lo_t lo;182 entry_hi_t hi;183 202 pte_t *pte; 184 203 … … 188 207 * Locate the faulting entry in TLB. 189 208 */ 190 hi.value = cp0_entry_hi_read();191 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);192 cp0_entry_hi_write(hi.value);193 209 tlbp(); 194 210 index.value = cp0_index_read(); 195 211 196 212 /* 197 * Fail if the entry is not in TLB. 213 * Emit warning if the entry is not in TLB. 214 * 215 * We do not assert on this because this could be a manifestation of 216 * an emulator bug, such as QEMU Bug #1128935: 217 * https://bugs.launchpad.net/qemu/+bug/1128935 198 218 */ 199 ASSERT(!index.p); 200 201 pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate); 202 if (pte) { 219 if (index.p) { 220 log(LF_ARCH, LVL_WARN, "%s: TLBP failed in exception handler (badvaddr=%#" 221 PRIxn ", ASID=%d).\n", __func__, badvaddr, 222 AS ? AS->asid : -1); 223 return; 224 } 225 226 pte = page_mapping_find(AS, badvaddr, true); 227 if (pte && pte->p && pte->w) { 203 228 /* 204 229 * Read the faulting TLB entry. … … 218 243 * The entry is to be updated in TLB. 219 244 */ 220 if ( (badvaddr / PAGE_SIZE) % 2== 0)245 if (BANK_SELECT_BIT(badvaddr) == 0) 221 246 cp0_entry_lo0_write(lo.value); 222 247 else 223 248 cp0_entry_lo1_write(lo.value); 224 cp0_pagemask_write(TLB_PAGE_MASK_16K);225 249 tlbwi(); 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; 250 return; 251 } 252 253 (void) as_page_fault(badvaddr, PF_ACCESS_WRITE, istate); 270 254 } 271 255 … … 284 268 void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr) 285 269 { 286 hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2); 270 hi->value = 0; 271 hi->vpn2 = ADDR2HI_VPN2(ALIGN_DOWN(addr, PAGE_SIZE)); 287 272 hi->asid = asid; 288 273 } … … 291 276 void tlb_print(void) 292 277 { 293 page_mask_t mask ;294 entry_lo_t lo0, lo 1;278 page_mask_t mask, mask_save; 279 entry_lo_t lo0, lo0_save, lo1, lo1_save; 295 280 entry_hi_t hi, hi_save; 296 281 unsigned int i; 297 282 298 283 hi_save.value = cp0_entry_hi_read(); 299 300 printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n"); 284 lo0_save.value = cp0_entry_lo0_read(); 285 lo1_save.value = cp0_entry_lo1_read(); 286 mask_save.value = cp0_pagemask_read(); 287 288 printf("[nr] [asid] [vpn2 ] [mask] [gvdc] [pfn ]\n"); 301 289 302 290 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 309 297 lo1.value = cp0_entry_lo1_read(); 310 298 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);299 printf("%-4u %-6u %0#10x %-#6x %1u%1u%1u%1u %0#10x\n", 300 i, hi.asid, HI_VPN22ADDR(hi.vpn2), mask.mask, 301 lo0.g, lo0.v, lo0.d, lo0.c, LO_PFN2ADDR(lo0.pfn)); 302 printf(" %1u%1u%1u%1u %0#10x\n", 303 lo1.g, lo1.v, lo1.d, lo1.c, LO_PFN2ADDR(lo1.pfn)); 316 304 } 317 305 318 306 cp0_entry_hi_write(hi_save.value); 307 cp0_entry_lo0_write(lo0_save.value); 308 cp0_entry_lo1_write(lo1_save.value); 309 cp0_pagemask_write(mask_save.value); 319 310 } 320 311 … … 322 313 void tlb_invalidate_all(void) 323 314 { 324 ipl_t ipl;325 315 entry_lo_t lo0, lo1; 326 316 entry_hi_t hi_save; 327 317 int i; 328 318 319 ASSERT(interrupts_disabled()); 320 329 321 hi_save.value = cp0_entry_hi_read(); 330 ipl = interrupts_disable();331 322 332 323 for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) { … … 346 337 } 347 338 348 interrupts_restore(ipl);349 339 cp0_entry_hi_write(hi_save.value); 350 340 } … … 356 346 void tlb_invalidate_asid(asid_t asid) 357 347 { 358 ipl_t ipl;359 348 entry_lo_t lo0, lo1; 360 349 entry_hi_t hi, hi_save; 361 350 int i; 362 351 352 ASSERT(interrupts_disabled()); 363 353 ASSERT(asid != ASID_INVALID); 364 354 365 355 hi_save.value = cp0_entry_hi_read(); 366 ipl = interrupts_disable();367 356 368 357 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 386 375 } 387 376 388 interrupts_restore(ipl);389 377 cp0_entry_hi_write(hi_save.value); 390 378 } … … 400 388 { 401 389 unsigned int i; 402 ipl_t ipl;403 390 entry_lo_t lo0, lo1; 404 391 entry_hi_t hi, hi_save; 405 392 tlb_index_t index; 393 394 ASSERT(interrupts_disabled()); 406 395 407 396 if (asid == ASID_INVALID) … … 409 398 410 399 hi_save.value = cp0_entry_hi_read(); 411 ipl = interrupts_disable();412 400 413 401 for (i = 0; i < cnt + 1; i += 2) { 414 hi.value = 0;415 402 tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE); 416 403 cp0_entry_hi_write(hi.value); … … 439 426 } 440 427 441 interrupts_restore(ipl);442 428 cp0_entry_hi_write(hi_save.value); 443 429 }
Note:
See TracChangeset
for help on using the changeset viewer.