Changes in kernel/arch/ppc32/src/mm/tlb.c [655f70b:7e752b2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/ppc32/src/mm/tlb.c
r655f70b r7e752b2 33 33 */ 34 34 35 #include <mm/tlb.h> 35 36 #include <arch/mm/tlb.h> 37 #include <arch/interrupt.h> 36 38 #include <interrupt.h> 37 #include <typedefs.h> 38 39 void tlb_refill(unsigned int n, istate_t *istate) 40 { 41 uint32_t tlbmiss; 42 ptehi_t ptehi; 43 ptelo_t ptelo; 44 45 asm volatile ( 46 "mfspr %[tlbmiss], 980\n" 47 "mfspr %[ptehi], 981\n" 48 "mfspr %[ptelo], 982\n" 49 : [tlbmiss] "=r" (tlbmiss), 50 [ptehi] "=r" (ptehi), 51 [ptelo] "=r" (ptelo) 52 ); 53 39 #include <mm/as.h> 40 #include <mm/page.h> 41 #include <arch.h> 42 #include <print.h> 43 #include <macros.h> 44 #include <symtab.h> 45 46 static unsigned int seed = 10; 47 static unsigned int seed_real 48 __attribute__ ((section("K_UNMAPPED_DATA_START"))) = 42; 49 50 /** Try to find PTE for faulting address 51 * 52 * @param as Address space. 53 * @param lock Lock/unlock the address space. 54 * @param badvaddr Faulting virtual address. 55 * @param access Access mode that caused the fault. 56 * @param istate Pointer to interrupted state. 57 * @param pfrc Pointer to variable where as_page_fault() return code 58 * will be stored. 59 * 60 * @return PTE on success, NULL otherwise. 61 * 62 */ 63 static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access, 64 istate_t *istate, int *pfrc) 65 { 66 ASSERT(mutex_locked(&as->lock)); 67 68 /* 69 * Check if the mapping exists in page tables. 70 */ 71 pte_t *pte = page_mapping_find(as, badvaddr); 72 if ((pte) && (pte->present)) { 73 /* 74 * Mapping found in page tables. 75 * Immediately succeed. 76 */ 77 return pte; 78 } else { 79 /* 80 * Mapping not found in page tables. 81 * Resort to higher-level page fault handler. 82 */ 83 page_table_unlock(as, true); 84 85 int rc = as_page_fault(badvaddr, access, istate); 86 switch (rc) { 87 case AS_PF_OK: 88 /* 89 * The higher-level page fault handler succeeded, 90 * The mapping ought to be in place. 91 */ 92 page_table_lock(as, true); 93 pte = page_mapping_find(as, badvaddr); 94 ASSERT((pte) && (pte->present)); 95 *pfrc = 0; 96 return pte; 97 case AS_PF_DEFER: 98 page_table_lock(as, true); 99 *pfrc = rc; 100 return NULL; 101 case AS_PF_FAULT: 102 page_table_lock(as, true); 103 *pfrc = rc; 104 return NULL; 105 default: 106 panic("Unexpected rc (%d).", rc); 107 } 108 } 109 } 110 111 static void pht_refill_fail(uintptr_t badvaddr, istate_t *istate) 112 { 113 fault_if_from_uspace(istate, "PHT Refill Exception on %p.", 114 (void *) badvaddr); 115 panic_memtrap(istate, PF_ACCESS_UNKNOWN, badvaddr, 116 "PHT Refill Exception."); 117 } 118 119 static void pht_insert(const uintptr_t vaddr, const pte_t *pte) 120 { 121 uint32_t page = (vaddr >> 12) & 0xffff; 122 uint32_t api = (vaddr >> 22) & 0x3f; 123 124 uint32_t vsid = sr_get(vaddr); 125 uint32_t sdr1 = sdr1_get(); 126 127 // FIXME: compute size of PHT exactly 128 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000); 129 130 /* Primary hash (xor) */ 131 uint32_t h = 0; 132 uint32_t hash = vsid ^ page; 133 uint32_t base = (hash & 0x3ff) << 3; 134 uint32_t i; 135 bool found = false; 136 137 /* Find colliding PTE in PTEG */ 138 for (i = 0; i < 8; i++) { 139 if ((phte[base + i].v) 140 && (phte[base + i].vsid == vsid) 141 && (phte[base + i].api == api) 142 && (phte[base + i].h == 0)) { 143 found = true; 144 break; 145 } 146 } 147 148 if (!found) { 149 /* Find unused PTE in PTEG */ 150 for (i = 0; i < 8; i++) { 151 if (!phte[base + i].v) { 152 found = true; 153 break; 154 } 155 } 156 } 157 158 if (!found) { 159 /* Secondary hash (not) */ 160 uint32_t base2 = (~hash & 0x3ff) << 3; 161 162 /* Find colliding PTE in PTEG */ 163 for (i = 0; i < 8; i++) { 164 if ((phte[base2 + i].v) 165 && (phte[base2 + i].vsid == vsid) 166 && (phte[base2 + i].api == api) 167 && (phte[base2 + i].h == 1)) { 168 found = true; 169 base = base2; 170 h = 1; 171 break; 172 } 173 } 174 175 if (!found) { 176 /* Find unused PTE in PTEG */ 177 for (i = 0; i < 8; i++) { 178 if (!phte[base2 + i].v) { 179 found = true; 180 base = base2; 181 h = 1; 182 break; 183 } 184 } 185 } 186 187 if (!found) 188 i = RANDI(seed) % 8; 189 } 190 191 phte[base + i].v = 1; 192 phte[base + i].vsid = vsid; 193 phte[base + i].h = h; 194 phte[base + i].api = api; 195 phte[base + i].rpn = pte->pfn; 196 phte[base + i].r = 0; 197 phte[base + i].c = 0; 198 phte[base + i].wimg = (pte->page_cache_disable ? WIMG_NO_CACHE : 0); 199 phte[base + i].pp = 2; // FIXME 200 } 201 202 /** Process Instruction/Data Storage Exception 203 * 204 * @param n Exception vector number. 205 * @param istate Interrupted register context. 206 * 207 */ 208 void pht_refill(unsigned int n, istate_t *istate) 209 { 210 as_t *as = (AS == NULL) ? AS_KERNEL : AS; 211 uintptr_t badvaddr; 212 213 if (n == VECTOR_DATA_STORAGE) 214 badvaddr = istate->dar; 215 else 216 badvaddr = istate->pc; 217 218 page_table_lock(as, true); 219 220 int pfrc; 221 pte_t *pte = find_mapping_and_check(as, badvaddr, 222 PF_ACCESS_READ /* FIXME */, istate, &pfrc); 223 224 if (!pte) { 225 switch (pfrc) { 226 case AS_PF_FAULT: 227 goto fail; 228 break; 229 case AS_PF_DEFER: 230 /* 231 * The page fault came during copy_from_uspace() 232 * or copy_to_uspace(). 233 */ 234 page_table_unlock(as, true); 235 return; 236 default: 237 panic("Unexpected pfrc (%d).", pfrc); 238 } 239 } 240 241 /* Record access to PTE */ 242 pte->accessed = 1; 243 pht_insert(badvaddr, pte); 244 245 page_table_unlock(as, true); 246 return; 247 248 fail: 249 page_table_unlock(as, true); 250 pht_refill_fail(badvaddr, istate); 251 } 252 253 /** Process Instruction/Data Storage Exception in Real Mode 254 * 255 * @param n Exception vector number. 256 * @param istate Interrupted register context. 257 * 258 */ 259 bool pht_refill_real(unsigned int n, istate_t *istate) 260 { 261 uintptr_t badvaddr; 262 263 if (n == VECTOR_DATA_STORAGE) 264 badvaddr = istate->dar; 265 else 266 badvaddr = istate->pc; 267 268 uint32_t physmem = physmem_top(); 269 270 if ((badvaddr < PA2KA(0)) || (badvaddr >= PA2KA(physmem))) 271 return false; 272 273 uint32_t page = (badvaddr >> 12) & 0xffff; 274 uint32_t api = (badvaddr >> 22) & 0x3f; 275 276 uint32_t vsid = sr_get(badvaddr); 277 uint32_t sdr1 = sdr1_get(); 278 279 // FIXME: compute size of PHT exactly 280 phte_t *phte_real = (phte_t *) (sdr1 & 0xffff0000); 281 282 /* Primary hash (xor) */ 283 uint32_t h = 0; 284 uint32_t hash = vsid ^ page; 285 uint32_t base = (hash & 0x3ff) << 3; 286 uint32_t i; 287 bool found = false; 288 289 /* Find colliding PTE in PTEG */ 290 for (i = 0; i < 8; i++) { 291 if ((phte_real[base + i].v) 292 && (phte_real[base + i].vsid == vsid) 293 && (phte_real[base + i].api == api) 294 && (phte_real[base + i].h == 0)) { 295 found = true; 296 break; 297 } 298 } 299 300 if (!found) { 301 /* Find unused PTE in PTEG */ 302 for (i = 0; i < 8; i++) { 303 if (!phte_real[base + i].v) { 304 found = true; 305 break; 306 } 307 } 308 } 309 310 if (!found) { 311 /* Secondary hash (not) */ 312 uint32_t base2 = (~hash & 0x3ff) << 3; 313 314 /* Find colliding PTE in PTEG */ 315 for (i = 0; i < 8; i++) { 316 if ((phte_real[base2 + i].v) 317 && (phte_real[base2 + i].vsid == vsid) 318 && (phte_real[base2 + i].api == api) 319 && (phte_real[base2 + i].h == 1)) { 320 found = true; 321 base = base2; 322 h = 1; 323 break; 324 } 325 } 326 327 if (!found) { 328 /* Find unused PTE in PTEG */ 329 for (i = 0; i < 8; i++) { 330 if (!phte_real[base2 + i].v) { 331 found = true; 332 base = base2; 333 h = 1; 334 break; 335 } 336 } 337 } 338 339 if (!found) { 340 /* Use secondary hash to avoid collisions 341 with usual PHT refill handler. */ 342 i = RANDI(seed_real) % 8; 343 base = base2; 344 h = 1; 345 } 346 } 347 348 phte_real[base + i].v = 1; 349 phte_real[base + i].vsid = vsid; 350 phte_real[base + i].h = h; 351 phte_real[base + i].api = api; 352 phte_real[base + i].rpn = KA2PA(badvaddr) >> 12; 353 phte_real[base + i].r = 0; 354 phte_real[base + i].c = 0; 355 phte_real[base + i].wimg = 0; 356 phte_real[base + i].pp = 2; // FIXME 357 358 return true; 359 } 360 361 /** Process ITLB/DTLB Miss Exception in Real Mode 362 * 363 * 364 */ 365 void tlb_refill_real(unsigned int n, uint32_t tlbmiss, ptehi_t ptehi, 366 ptelo_t ptelo, istate_t *istate) 367 { 54 368 uint32_t badvaddr = tlbmiss & 0xfffffffc; 55 369 uint32_t physmem = physmem_top(); … … 81 395 void tlb_invalidate_all(void) 82 396 { 397 uint32_t index; 398 83 399 asm volatile ( 400 "li %[index], 0\n" 84 401 "sync\n" 85 ); 86 87 for (unsigned int i = 0; i < 0x00040000; i += 0x00001000) { 88 asm volatile ( 89 "tlbie %[i]\n" 90 :: [i] "r" (i) 91 ); 92 } 93 94 asm volatile ( 402 403 ".rept 64\n" 404 " tlbie %[index]\n" 405 " addi %[index], %[index], 0x1000\n" 406 ".endr\n" 407 95 408 "eieio\n" 96 409 "tlbsync\n" 97 410 "sync\n" 411 : [index] "=r" (index) 98 412 ); 99 413 } … … 101 415 void tlb_invalidate_asid(asid_t asid) 102 416 { 417 uint32_t sdr1 = sdr1_get(); 418 419 // FIXME: compute size of PHT exactly 420 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000); 421 422 size_t i; 423 for (i = 0; i < 8192; i++) { 424 if ((phte[i].v) && (phte[i].vsid >= (asid << 4)) && 425 (phte[i].vsid < ((asid << 4) + 16))) 426 phte[i].v = 0; 427 } 428 103 429 tlb_invalidate_all(); 104 430 } … … 106 432 void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt) 107 433 { 434 // TODO 108 435 tlb_invalidate_all(); 109 436 }
Note:
See TracChangeset
for help on using the changeset viewer.