Changeset a33f0a6 in mainline for kernel/arch/ppc32/src/mm/tlb.c
- Timestamp:
- 2011-08-03T17:34:57Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1940326
- Parents:
- 52a79081 (diff), 3fab770 (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/ppc32/src/mm/tlb.c
r52a79081 ra33f0a6 33 33 */ 34 34 35 #include <mm/tlb.h>36 35 #include <arch/mm/tlb.h> 37 #include <arch/interrupt.h>38 36 #include <interrupt.h> 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> 37 #include <typedefs.h> 45 38 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) 39 void tlb_refill(unsigned int n, istate_t *istate) 65 40 { 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; 41 uint32_t tlbmiss; 42 ptehi_t ptehi; 43 ptelo_t ptelo; 123 44 124 uint32_t vsid = sr_get(vaddr); 125 uint32_t sdr1 = sdr1_get(); 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 ); 126 53 127 // FIXME: compute size of PHT exactly128 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; // FIXME200 }201 202 /** Process Instruction/Data Storage Exception203 *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 else216 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 Mode254 *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 else266 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 exactly280 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 collisions341 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; // FIXME357 358 return true;359 }360 361 /** Process ITLB/DTLB Miss Exception in Real Mode362 *363 *364 */365 void tlb_refill_real(unsigned int n, uint32_t tlbmiss, ptehi_t ptehi,366 ptelo_t ptelo, istate_t *istate)367 {368 54 uint32_t badvaddr = tlbmiss & 0xfffffffc; 369 55 uint32_t physmem = physmem_top(); … … 395 81 void tlb_invalidate_all(void) 396 82 { 397 uint32_t index; 83 asm volatile ( 84 "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 } 398 93 399 94 asm volatile ( 400 "li %[index], 0\n"401 "sync\n"402 403 ".rept 64\n"404 " tlbie %[index]\n"405 " addi %[index], %[index], 0x1000\n"406 ".endr\n"407 408 95 "eieio\n" 409 96 "tlbsync\n" 410 97 "sync\n" 411 : [index] "=r" (index)412 98 ); 413 99 } … … 415 101 void tlb_invalidate_asid(asid_t asid) 416 102 { 417 uint32_t sdr1 = sdr1_get();418 419 // FIXME: compute size of PHT exactly420 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 429 103 tlb_invalidate_all(); 430 104 } … … 432 106 void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt) 433 107 { 434 // TODO435 108 tlb_invalidate_all(); 436 109 }
Note:
See TracChangeset
for help on using the changeset viewer.