Changeset 06b0211b in mainline for kernel/arch/mips32/src/mm/tlb.c
- Timestamp:
- 2013-04-29T11:29:45Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- aa2b32c
- Parents:
- ba4799a (diff), df956b9b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/mips32/src/mm/tlb.c
rba4799a r06b0211b 48 48 #include <symtab.h> 49 49 50 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *); 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 51 60 52 61 /** Initialize TLB. … … 84 93 { 85 94 entry_lo_t lo; 86 entry_hi_t hi;87 asid_t asid;88 95 uintptr_t badvaddr; 89 96 pte_t *pte; 90 97 91 98 badvaddr = cp0_badvaddr_read(); 92 asid = AS->asid; 93 94 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 95 if (pte) { 99 100 pte = page_mapping_find(AS, badvaddr, true); 101 if (pte && pte->p) { 96 102 /* 97 103 * Record access to PTE. … … 99 105 pte->a = 1; 100 106 101 tlb_prepare_entry_hi(&hi, asid, badvaddr);102 107 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, 103 108 pte->cacheable, pte->pfn); … … 106 111 * New entry is to be inserted into TLB 107 112 */ 108 cp0_entry_hi_write(hi.value); 109 if ((badvaddr / PAGE_SIZE) % 2 == 0) { 113 if (BANK_SELECT_BIT(badvaddr) == 0) { 110 114 cp0_entry_lo0_write(lo.value); 111 115 cp0_entry_lo1_write(0); … … 116 120 cp0_pagemask_write(TLB_PAGE_MASK_16K); 117 121 tlbwr(); 118 } 122 return; 123 } 124 125 (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate); 119 126 } 120 127 … … 125 132 void tlb_invalid(istate_t *istate) 126 133 { 134 entry_lo_t lo; 127 135 tlb_index_t index; 128 136 uintptr_t badvaddr; 129 entry_lo_t lo;130 entry_hi_t hi;131 137 pte_t *pte; 132 133 badvaddr = cp0_badvaddr_read();134 138 135 139 /* 136 140 * Locate the faulting entry in TLB. 137 141 */ 138 hi.value = cp0_entry_hi_read();139 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);140 cp0_entry_hi_write(hi.value);141 142 tlbp(); 142 143 index.value = cp0_index_read(); 143 144 145 #if defined(PROCESSOR_4Kc) 146 /* 147 * This can happen on a 4Kc when Status.EXL is 1 and there is a TLB miss. 148 * EXL is 1 when interrupts are disabled. The combination of a TLB miss 149 * and disabled interrupts is possible in copy_to/from_uspace(). 150 */ 151 if (index.p) { 152 tlb_refill(istate); 153 return; 154 } 155 #endif 156 144 157 ASSERT(!index.p); 145 158 146 pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate); 147 if (pte) { 159 badvaddr = cp0_badvaddr_read(); 160 161 pte = page_mapping_find(AS, badvaddr, true); 162 if (pte && pte->p) { 148 163 /* 149 164 * Read the faulting TLB entry. … … 162 177 * The entry is to be updated in TLB. 163 178 */ 164 if ( (badvaddr / PAGE_SIZE) % 2== 0)179 if (BANK_SELECT_BIT(badvaddr) == 0) 165 180 cp0_entry_lo0_write(lo.value); 166 181 else 167 182 cp0_entry_lo1_write(lo.value); 168 cp0_pagemask_write(TLB_PAGE_MASK_16K);169 183 tlbwi(); 170 } 184 return; 185 } 186 187 (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate); 171 188 } 172 189 … … 177 194 void tlb_modified(istate_t *istate) 178 195 { 196 entry_lo_t lo; 179 197 tlb_index_t index; 180 198 uintptr_t badvaddr; 181 entry_lo_t lo;182 entry_hi_t hi;183 199 pte_t *pte; 184 200 … … 188 204 * Locate the faulting entry in TLB. 189 205 */ 190 hi.value = cp0_entry_hi_read();191 tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);192 cp0_entry_hi_write(hi.value);193 206 tlbp(); 194 207 index.value = cp0_index_read(); 195 208 196 209 /* 197 * Fail if the entry is not in TLB. 210 * Emit warning if the entry is not in TLB. 211 * 212 * We do not assert on this because this could be a manifestation of 213 * an emulator bug, such as QEMU Bug #1128935: 214 * https://bugs.launchpad.net/qemu/+bug/1128935 198 215 */ 199 ASSERT(!index.p); 200 201 pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate); 202 if (pte) { 216 if (index.p) { 217 printf("%s: TLBP failed in exception handler (badvaddr=%#" 218 PRIxn ", ASID=%d).\n", __func__, badvaddr, 219 AS ? AS->asid : -1); 220 return; 221 } 222 223 pte = page_mapping_find(AS, badvaddr, true); 224 if (pte && pte->p && pte->w) { 203 225 /* 204 226 * Read the faulting TLB entry. … … 218 240 * The entry is to be updated in TLB. 219 241 */ 220 if ( (badvaddr / PAGE_SIZE) % 2== 0)242 if (BANK_SELECT_BIT(badvaddr) == 0) 221 243 cp0_entry_lo0_write(lo.value); 222 244 else 223 245 cp0_entry_lo1_write(lo.value); 224 cp0_pagemask_write(TLB_PAGE_MASK_16K);225 246 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; 247 return; 248 } 249 250 (void) as_page_fault(badvaddr, PF_ACCESS_WRITE, istate); 270 251 } 271 252 … … 284 265 void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr) 285 266 { 286 hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2); 267 hi->value = 0; 268 hi->vpn2 = ADDR2VPN2(ALIGN_DOWN(addr, PAGE_SIZE)); 287 269 hi->asid = asid; 288 270 } … … 291 273 void tlb_print(void) 292 274 { 293 page_mask_t mask ;294 entry_lo_t lo0, lo 1;275 page_mask_t mask, mask_save; 276 entry_lo_t lo0, lo0_save, lo1, lo1_save; 295 277 entry_hi_t hi, hi_save; 296 278 unsigned int i; 297 279 298 280 hi_save.value = cp0_entry_hi_read(); 299 300 printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n"); 281 lo0_save.value = cp0_entry_lo0_read(); 282 lo1_save.value = cp0_entry_lo1_read(); 283 mask_save.value = cp0_pagemask_read(); 284 285 printf("[nr] [asid] [vpn2 ] [mask] [gvdc] [pfn ]\n"); 301 286 302 287 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 309 294 lo1.value = cp0_entry_lo1_read(); 310 295 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);296 printf("%-4u %-6u %0#10x %-#6x %1u%1u%1u%1u %0#10x\n", 297 i, hi.asid, VPN22ADDR(hi.vpn2), mask.mask, 298 lo0.g, lo0.v, lo0.d, lo0.c, PFN2ADDR(lo0.pfn)); 299 printf(" %1u%1u%1u%1u %0#10x\n", 300 lo1.g, lo1.v, lo1.d, lo1.c, PFN2ADDR(lo1.pfn)); 316 301 } 317 302 318 303 cp0_entry_hi_write(hi_save.value); 304 cp0_entry_lo0_write(lo0_save.value); 305 cp0_entry_lo1_write(lo1_save.value); 306 cp0_pagemask_write(mask_save.value); 319 307 } 320 308 … … 322 310 void tlb_invalidate_all(void) 323 311 { 324 ipl_t ipl;325 312 entry_lo_t lo0, lo1; 326 313 entry_hi_t hi_save; 327 314 int i; 328 315 316 ASSERT(interrupts_disabled()); 317 329 318 hi_save.value = cp0_entry_hi_read(); 330 ipl = interrupts_disable();331 319 332 320 for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) { … … 346 334 } 347 335 348 interrupts_restore(ipl);349 336 cp0_entry_hi_write(hi_save.value); 350 337 } … … 356 343 void tlb_invalidate_asid(asid_t asid) 357 344 { 358 ipl_t ipl;359 345 entry_lo_t lo0, lo1; 360 346 entry_hi_t hi, hi_save; 361 347 int i; 362 348 349 ASSERT(interrupts_disabled()); 363 350 ASSERT(asid != ASID_INVALID); 364 351 365 352 hi_save.value = cp0_entry_hi_read(); 366 ipl = interrupts_disable();367 353 368 354 for (i = 0; i < TLB_ENTRY_COUNT; i++) { … … 386 372 } 387 373 388 interrupts_restore(ipl);389 374 cp0_entry_hi_write(hi_save.value); 390 375 } … … 400 385 { 401 386 unsigned int i; 402 ipl_t ipl;403 387 entry_lo_t lo0, lo1; 404 388 entry_hi_t hi, hi_save; 405 389 tlb_index_t index; 390 391 ASSERT(interrupts_disabled()); 406 392 407 393 if (asid == ASID_INVALID) … … 409 395 410 396 hi_save.value = cp0_entry_hi_read(); 411 ipl = interrupts_disable();412 397 413 398 for (i = 0; i < cnt + 1; i += 2) { 414 hi.value = 0;415 399 tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE); 416 400 cp0_entry_hi_write(hi.value); … … 439 423 } 440 424 441 interrupts_restore(ipl);442 425 cp0_entry_hi_write(hi_save.value); 443 426 }
Note:
See TracChangeset
for help on using the changeset viewer.