Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/ppc32/src/mm/tlb.c

    r655f70b r7e752b2  
    3333 */
    3434
     35#include <mm/tlb.h>
    3536#include <arch/mm/tlb.h>
     37#include <arch/interrupt.h>
    3638#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
     46static unsigned int seed = 10;
     47static 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 */
     63static 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
     111static 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
     119static 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 */
     208void 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       
     248fail:
     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 */
     259bool 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 */
     365void tlb_refill_real(unsigned int n, uint32_t tlbmiss, ptehi_t ptehi,
     366    ptelo_t ptelo, istate_t *istate)
     367{
    54368        uint32_t badvaddr = tlbmiss & 0xfffffffc;
    55369        uint32_t physmem = physmem_top();
     
    81395void tlb_invalidate_all(void)
    82396{
     397        uint32_t index;
     398       
    83399        asm volatile (
     400                "li %[index], 0\n"
    84401                "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               
    95408                "eieio\n"
    96409                "tlbsync\n"
    97410                "sync\n"
     411                : [index] "=r" (index)
    98412        );
    99413}
     
    101415void tlb_invalidate_asid(asid_t asid)
    102416{
     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       
    103429        tlb_invalidate_all();
    104430}
     
    106432void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
    107433{
     434        // TODO
    108435        tlb_invalidate_all();
    109436}
Note: See TracChangeset for help on using the changeset viewer.