Ignore:
File:
1 edited

Legend:

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

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