Ignore:
File:
1 edited

Legend:

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

    r655f70b rc99693a  
    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>
     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 = 42;
     47
     48/** Try to find PTE for faulting address
     49 *
     50 * @param as       Address space.
     51 * @param badvaddr Faulting virtual address.
     52 * @param access   Access mode that caused the fault.
     53 * @param istate   Pointer to interrupted state.
     54 * @param pfrc     Pointer to variable where as_page_fault() return code
     55 *                 will be stored.
     56 *
     57 * @return PTE on success, NULL otherwise.
     58 *
     59 */
     60static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access,
     61    istate_t *istate, int *pfrc)
     62{
     63        /*
     64         * Check if the mapping exists in page tables.
     65         */
     66        pte_t *pte = page_mapping_find(as, badvaddr, true);
     67        if ((pte) && (pte->present)) {
     68                /*
     69                 * Mapping found in page tables.
     70                 * Immediately succeed.
     71                 */
     72                return pte;
     73        } else {
     74                /*
     75                 * Mapping not found in page tables.
     76                 * Resort to higher-level page fault handler.
     77                 */
     78                int rc = as_page_fault(badvaddr, access, istate);
     79                switch (rc) {
     80                case AS_PF_OK:
     81                        /*
     82                         * The higher-level page fault handler succeeded,
     83                         * The mapping ought to be in place.
     84                         */
     85                        pte = page_mapping_find(as, badvaddr, true);
     86                        ASSERT((pte) && (pte->present));
     87                        *pfrc = 0;
     88                        return pte;
     89                case AS_PF_DEFER:
     90                        *pfrc = rc;
     91                        return NULL;
     92                case AS_PF_FAULT:
     93                        *pfrc = rc;
     94                        return NULL;
     95                default:
     96                        panic("Unexpected rc (%d).", rc);
     97                }
     98        }
     99}
     100
     101static void pht_refill_fail(uintptr_t badvaddr, istate_t *istate)
     102{
     103        fault_if_from_uspace(istate, "PHT Refill Exception on %p.",
     104            (void *) badvaddr);
     105        panic_memtrap(istate, PF_ACCESS_UNKNOWN, badvaddr,
     106            "PHT Refill Exception.");
     107}
     108
     109static void pht_insert(const uintptr_t vaddr, const pte_t *pte)
     110{
     111        uint32_t page = (vaddr >> 12) & 0xffff;
     112        uint32_t api = (vaddr >> 22) & 0x3f;
     113       
     114        uint32_t vsid = sr_get(vaddr);
     115        uint32_t sdr1 = sdr1_get();
     116       
     117        // FIXME: compute size of PHT exactly
     118        phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
     119       
     120        /* Primary hash (xor) */
     121        uint32_t h = 0;
     122        uint32_t hash = vsid ^ page;
     123        uint32_t base = (hash & 0x3ff) << 3;
     124        uint32_t i;
     125        bool found = false;
     126       
     127        /* Find colliding PTE in PTEG */
     128        for (i = 0; i < 8; i++) {
     129                if ((phte[base + i].v)
     130                    && (phte[base + i].vsid == vsid)
     131                    && (phte[base + i].api == api)
     132                    && (phte[base + i].h == 0)) {
     133                        found = true;
     134                        break;
     135                }
     136        }
     137       
     138        if (!found) {
     139                /* Find unused PTE in PTEG */
     140                for (i = 0; i < 8; i++) {
     141                        if (!phte[base + i].v) {
     142                                found = true;
     143                                break;
     144                        }
     145                }
     146        }
     147       
     148        if (!found) {
     149                /* Secondary hash (not) */
     150                uint32_t base2 = (~hash & 0x3ff) << 3;
     151               
     152                /* Find colliding PTE in PTEG */
     153                for (i = 0; i < 8; i++) {
     154                        if ((phte[base2 + i].v)
     155                            && (phte[base2 + i].vsid == vsid)
     156                            && (phte[base2 + i].api == api)
     157                            && (phte[base2 + i].h == 1)) {
     158                                found = true;
     159                                base = base2;
     160                                h = 1;
     161                                break;
     162                        }
     163                }
     164               
     165                if (!found) {
     166                        /* Find unused PTE in PTEG */
     167                        for (i = 0; i < 8; i++) {
     168                                if (!phte[base2 + i].v) {
     169                                        found = true;
     170                                        base = base2;
     171                                        h = 1;
     172                                        break;
     173                                }
     174                        }
     175                }
     176               
     177                if (!found)
     178                        i = RANDI(seed) % 8;
     179        }
     180       
     181        phte[base + i].v = 1;
     182        phte[base + i].vsid = vsid;
     183        phte[base + i].h = h;
     184        phte[base + i].api = api;
     185        phte[base + i].rpn = pte->pfn;
     186        phte[base + i].r = 0;
     187        phte[base + i].c = 0;
     188        phte[base + i].wimg = (pte->page_cache_disable ? WIMG_NO_CACHE : 0);
     189        phte[base + i].pp = 2; // FIXME
     190}
     191
     192/** Process Instruction/Data Storage Exception
     193 *
     194 * @param n      Exception vector number.
     195 * @param istate Interrupted register context.
     196 *
     197 */
     198void pht_refill(unsigned int n, istate_t *istate)
     199{
     200        as_t *as = (AS == NULL) ? AS_KERNEL : AS;
     201        uintptr_t badvaddr;
     202       
     203        if (n == VECTOR_DATA_STORAGE)
     204                badvaddr = istate->dar;
     205        else
     206                badvaddr = istate->pc;
     207       
     208        int pfrc;
     209        pte_t *pte = find_mapping_and_check(as, badvaddr,
     210            PF_ACCESS_READ /* FIXME */, istate, &pfrc);
     211       
     212        if (!pte) {
     213                switch (pfrc) {
     214                case AS_PF_FAULT:
     215                        pht_refill_fail(badvaddr, istate);
     216                        return;
     217                case AS_PF_DEFER:
     218                        /*
     219                         * The page fault came during copy_from_uspace()
     220                         * or copy_to_uspace().
     221                         */
     222                        return;
     223                default:
     224                        panic("Unexpected pfrc (%d).", pfrc);
     225                }
     226        }
     227       
     228        /* Record access to PTE */
     229        pte->accessed = 1;
     230        pht_insert(badvaddr, pte);
     231}
    38232
    39233void tlb_refill(unsigned int n, istate_t *istate)
     
    81275void tlb_invalidate_all(void)
    82276{
     277        uint32_t index;
     278       
    83279        asm volatile (
     280                "li %[index], 0\n"
    84281                "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 (
     282               
     283                ".rept 64\n"
     284                "       tlbie %[index]\n"
     285                "       addi %[index], %[index], 0x1000\n"
     286                ".endr\n"
     287               
    95288                "eieio\n"
    96289                "tlbsync\n"
    97290                "sync\n"
     291                : [index] "=r" (index)
    98292        );
    99293}
     
    101295void tlb_invalidate_asid(asid_t asid)
    102296{
     297        uint32_t sdr1 = sdr1_get();
     298       
     299        // FIXME: compute size of PHT exactly
     300        phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
     301       
     302        size_t i;
     303        for (i = 0; i < 8192; i++) {
     304                if ((phte[i].v) && (phte[i].vsid >= (asid << 4)) &&
     305                    (phte[i].vsid < ((asid << 4) + 16)))
     306                        phte[i].v = 0;
     307        }
     308       
    103309        tlb_invalidate_all();
    104310}
     
    106312void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
    107313{
     314        // TODO
    108315        tlb_invalidate_all();
    109316}
Note: See TracChangeset for help on using the changeset viewer.