00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <mm/tlb.h>
00036 #include <arch/mm/tlb.h>
00037 #include <arch/interrupt.h>
00038 #include <mm/as.h>
00039 #include <arch.h>
00040 #include <print.h>
00041 #include <symtab.h>
00042
00043
00059 static pte_t *find_mapping_and_check(as_t *as, bool lock, __address badvaddr, int access, istate_t *istate, int *pfrc)
00060 {
00061
00062
00063
00064 pte_t *pte = page_mapping_find(as, badvaddr);
00065 if ((pte) && (pte->p)) {
00066
00067
00068
00069
00070 return pte;
00071 } else {
00072 int rc;
00073
00074
00075
00076
00077
00078 page_table_unlock(as, lock);
00079 switch (rc = as_page_fault(badvaddr, access, istate)) {
00080 case AS_PF_OK:
00081
00082
00083
00084
00085 page_table_lock(as, lock);
00086 pte = page_mapping_find(as, badvaddr);
00087 ASSERT((pte) && (pte->p));
00088 return pte;
00089 case AS_PF_DEFER:
00090 page_table_lock(as, lock);
00091 *pfrc = rc;
00092 return NULL;
00093 case AS_PF_FAULT:
00094 page_table_lock(as, lock);
00095 printf("Page fault.\n");
00096 *pfrc = rc;
00097 return NULL;
00098 default:
00099 panic("unexpected rc (%d)\n", rc);
00100 }
00101 }
00102 }
00103
00104
00105 static void pht_refill_fail(__address badvaddr, istate_t *istate)
00106 {
00107 char *symbol = "";
00108 char *sym2 = "";
00109
00110 char *s = get_symtab_entry(istate->pc);
00111 if (s)
00112 symbol = s;
00113 s = get_symtab_entry(istate->lr);
00114 if (s)
00115 sym2 = s;
00116 panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
00117 }
00118
00119
00120 static void pht_insert(const __address vaddr, const pfn_t pfn)
00121 {
00122 __u32 page = (vaddr >> 12) & 0xffff;
00123 __u32 api = (vaddr >> 22) & 0x3f;
00124
00125 __u32 vsid;
00126 asm volatile (
00127 "mfsrin %0, %1\n"
00128 : "=r" (vsid)
00129 : "r" (vaddr)
00130 );
00131
00132 __u32 sdr1;
00133 asm volatile (
00134 "mfsdr1 %0\n"
00135 : "=r" (sdr1)
00136 );
00137 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
00138
00139
00140 __u32 h = 0;
00141 __u32 hash = vsid ^ page;
00142 __u32 base = (hash & 0x3ff) << 3;
00143 __u32 i;
00144 bool found = false;
00145
00146
00147
00148 for (i = 0; i < 8; i++) {
00149 if ((!phte[base + i].v) || ((phte[base + i].vsid == vsid) && (phte[base + i].api == api))) {
00150 found = true;
00151 break;
00152 }
00153 }
00154
00155 if (!found) {
00156
00157 __u32 base2 = (~hash & 0x3ff) << 3;
00158
00159
00160
00161 for (i = 0; i < 8; i++) {
00162 if ((!phte[base2 + i].v) || ((phte[base2 + i].vsid == vsid) && (phte[base2 + i].api == api))) {
00163 found = true;
00164 base = base2;
00165 h = 1;
00166 break;
00167 }
00168 }
00169
00170 if (!found) {
00171
00172 i = page % 8;
00173 }
00174 }
00175
00176 phte[base + i].v = 1;
00177 phte[base + i].vsid = vsid;
00178 phte[base + i].h = h;
00179 phte[base + i].api = api;
00180 phte[base + i].rpn = pfn;
00181 phte[base + i].r = 0;
00182 phte[base + i].c = 0;
00183 phte[base + i].pp = 2;
00184 }
00185
00186
00187 static void pht_real_insert(const __address vaddr, const pfn_t pfn)
00188 {
00189 __u32 page = (vaddr >> 12) & 0xffff;
00190 __u32 api = (vaddr >> 22) & 0x3f;
00191
00192 __u32 vsid;
00193 asm volatile (
00194 "mfsrin %0, %1\n"
00195 : "=r" (vsid)
00196 : "r" (vaddr)
00197 );
00198
00199 __u32 sdr1;
00200 asm volatile (
00201 "mfsdr1 %0\n"
00202 : "=r" (sdr1)
00203 );
00204 phte_t *phte_physical = (phte_t *) (sdr1 & 0xffff0000);
00205
00206
00207 __u32 h = 0;
00208 __u32 hash = vsid ^ page;
00209 __u32 base = (hash & 0x3ff) << 3;
00210 __u32 i;
00211 bool found = false;
00212
00213
00214
00215 for (i = 0; i < 8; i++) {
00216 if ((!phte_physical[base + i].v) || ((phte_physical[base + i].vsid == vsid) && (phte_physical[base + i].api == api))) {
00217 found = true;
00218 break;
00219 }
00220 }
00221
00222 if (!found) {
00223
00224 __u32 base2 = (~hash & 0x3ff) << 3;
00225
00226
00227
00228 for (i = 0; i < 8; i++) {
00229 if ((!phte_physical[base2 + i].v) || ((phte_physical[base2 + i].vsid == vsid) && (phte_physical[base2 + i].api == api))) {
00230 found = true;
00231 base = base2;
00232 h = 1;
00233 break;
00234 }
00235 }
00236
00237 if (!found) {
00238
00239 i = page % 8;
00240 }
00241 }
00242
00243 phte_physical[base + i].v = 1;
00244 phte_physical[base + i].vsid = vsid;
00245 phte_physical[base + i].h = h;
00246 phte_physical[base + i].api = api;
00247 phte_physical[base + i].rpn = pfn;
00248 phte_physical[base + i].r = 0;
00249 phte_physical[base + i].c = 0;
00250 phte_physical[base + i].pp = 2;
00251 }
00252
00253
00260 void pht_refill(int n, istate_t *istate)
00261 {
00262 __address badvaddr;
00263 pte_t *pte;
00264 int pfrc;
00265 as_t *as;
00266 bool lock;
00267
00268 if (AS == NULL) {
00269 as = AS_KERNEL;
00270 lock = false;
00271 } else {
00272 as = AS;
00273 lock = true;
00274 }
00275
00276 if (n == VECTOR_DATA_STORAGE) {
00277 asm volatile (
00278 "mfdar %0\n"
00279 : "=r" (badvaddr)
00280 );
00281 } else
00282 badvaddr = istate->pc;
00283
00284 page_table_lock(as, lock);
00285
00286 pte = find_mapping_and_check(as, lock, badvaddr, PF_ACCESS_READ , istate, &pfrc);
00287 if (!pte) {
00288 switch (pfrc) {
00289 case AS_PF_FAULT:
00290 goto fail;
00291 break;
00292 case AS_PF_DEFER:
00293
00294
00295
00296
00297 page_table_unlock(as, lock);
00298 return;
00299 default:
00300 panic("Unexpected pfrc (%d)\n", pfrc);
00301 }
00302 }
00303
00304 pte->a = 1;
00305 pht_insert(badvaddr, pte->pfn);
00306
00307 page_table_unlock(as, lock);
00308 return;
00309
00310 fail:
00311 page_table_unlock(as, lock);
00312 pht_refill_fail(badvaddr, istate);
00313 }
00314
00315
00322 bool pht_real_refill(int n, istate_t *istate)
00323 {
00324 __address badvaddr;
00325
00326 if (n == VECTOR_DATA_STORAGE) {
00327 asm volatile (
00328 "mfdar %0\n"
00329 : "=r" (badvaddr)
00330 );
00331 } else
00332 badvaddr = istate->pc;
00333
00334 __u32 physmem;
00335 asm volatile (
00336 "mfsprg3 %0\n"
00337 : "=r" (physmem)
00338 );
00339
00340 if ((badvaddr >= PA2KA(0)) && (badvaddr < PA2KA(physmem))) {
00341 pht_real_insert(badvaddr, KA2PA(badvaddr) >> 12);
00342 return true;
00343 }
00344
00345 return false;
00346 }
00347
00348
00349 void tlb_arch_init(void)
00350 {
00351 tlb_invalidate_all();
00352 }
00353
00354
00355 void tlb_invalidate_all(void)
00356 {
00357 asm volatile (
00358 "tlbia\n"
00359 "tlbsync\n"
00360 );
00361 }
00362
00363
00364 void tlb_invalidate_asid(asid_t asid)
00365 {
00366
00367 tlb_invalidate_all();
00368 }
00369
00370
00371 void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
00372 {
00373
00374 tlb_invalidate_all();
00375 }
00376
00377
00378 #define PRINT_BAT(name, ureg, lreg) \
00379 asm volatile ( \
00380 "mfspr %0," #ureg "\n" \
00381 "mfspr %1," #lreg "\n" \
00382 : "=r" (upper), "=r" (lower) \
00383 ); \
00384 mask = (upper & 0x1ffc) >> 2; \
00385 if (upper & 3) { \
00386 __u32 tmp = mask; \
00387 length = 128; \
00388 while (tmp) { \
00389 if ((tmp & 1) == 0) { \
00390 printf("ibat[0]: error in mask\n"); \
00391 break; \
00392 } \
00393 length <<= 1; \
00394 tmp >>= 1; \
00395 } \
00396 } else \
00397 length = 0; \
00398 printf(name ": page=%.*p frame=%.*p length=%d KB (mask=%#x)%s%s\n", sizeof(upper) * 2, upper & 0xffff0000, sizeof(lower) * 2, lower & 0xffff0000, length, mask, ((upper >> 1) & 1) ? " supervisor" : "", (upper & 1) ? " user" : "");
00399
00400
00401 void tlb_print(void)
00402 {
00403 __u32 sr;
00404
00405 for (sr = 0; sr < 16; sr++) {
00406 __u32 vsid;
00407 asm volatile (
00408 "mfsrin %0, %1\n"
00409 : "=r" (vsid)
00410 : "r" (sr << 28)
00411 );
00412 printf("vsid[%d]: VSID=%.*p (ASID=%d)%s%s\n", sr, sizeof(vsid) * 2, vsid & 0xffffff, (vsid & 0xffffff) >> 4, ((vsid >> 30) & 1) ? " supervisor" : "", ((vsid >> 29) & 1) ? " user" : "");
00413 }
00414
00415 __u32 upper;
00416 __u32 lower;
00417 __u32 mask;
00418 __u32 length;
00419
00420 PRINT_BAT("ibat[0]", 528, 529);
00421 PRINT_BAT("ibat[1]", 530, 531);
00422 PRINT_BAT("ibat[2]", 532, 533);
00423 PRINT_BAT("ibat[3]", 534, 535);
00424
00425 PRINT_BAT("dbat[0]", 536, 537);
00426 PRINT_BAT("dbat[1]", 538, 539);
00427 PRINT_BAT("dbat[2]", 540, 541);
00428 PRINT_BAT("dbat[3]", 542, 543);
00429 }
00430