tlb.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Martin Decky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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          * Check if the mapping exists in page tables.
00063          */     
00064         pte_t *pte = page_mapping_find(as, badvaddr);
00065         if ((pte) && (pte->p)) {
00066                 /*
00067                  * Mapping found in page tables.
00068                  * Immediately succeed.
00069                  */
00070                 return pte;
00071         } else {
00072                 int rc;
00073         
00074                 /*
00075                  * Mapping not found in page tables.
00076                  * Resort to higher-level page fault handler.
00077                  */
00078                 page_table_unlock(as, lock);
00079                 switch (rc = as_page_fault(badvaddr, access, istate)) {
00080                         case AS_PF_OK:
00081                                 /*
00082                                  * The higher-level page fault handler succeeded,
00083                                  * The mapping ought to be in place.
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         /* Primary hash (xor) */
00140         __u32 h = 0;
00141         __u32 hash = vsid ^ page;
00142         __u32 base = (hash & 0x3ff) << 3;
00143         __u32 i;
00144         bool found = false;
00145         
00146         /* Find unused or colliding
00147            PTE in PTEG */
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                 /* Secondary hash (not) */
00157                 __u32 base2 = (~hash & 0x3ff) << 3;
00158                 
00159                 /* Find unused or colliding
00160                    PTE in PTEG */
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                         // TODO: A/C precedence groups
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; // FIXME
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         /* Primary hash (xor) */
00207         __u32 h = 0;
00208         __u32 hash = vsid ^ page;
00209         __u32 base = (hash & 0x3ff) << 3;
00210         __u32 i;
00211         bool found = false;
00212         
00213         /* Find unused or colliding
00214            PTE in PTEG */
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                 /* Secondary hash (not) */
00224                 __u32 base2 = (~hash & 0x3ff) << 3;
00225                 
00226                 /* Find unused or colliding
00227                    PTE in PTEG */
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                         // TODO: A/C precedence groups
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; // FIXME
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 /* FIXME */, 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                                  * The page fault came during copy_from_uspace()
00295                                  * or copy_to_uspace().
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; /* Record access to PTE */
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         // TODO
00367         tlb_invalidate_all();
00368 }
00369 
00370 
00371 void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
00372 {
00373         // TODO
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 

Generated on Sun Jun 18 17:17:05 2006 for HelenOS Kernel (ppc32) by  doxygen 1.4.6