Ignore:
File:
1 edited

Legend:

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

    r26aafe8 r655f70b  
    3333 */
    3434
    35 #include <mm/tlb.h>
    3635#include <arch/mm/tlb.h>
    37 #include <arch/interrupt.h>
    3836#include <interrupt.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 
    46 static 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  */
    61 static 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 
    109 static 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 
    117 static 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  */
    206 void 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 }
     37#include <typedefs.h>
    24638
    24739void tlb_refill(unsigned int n, istate_t *istate)
     
    28981void tlb_invalidate_all(void)
    29082{
    291         uint32_t index;
     83        asm volatile (
     84                "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        }
    29293       
    29394        asm volatile (
    294                 "li %[index], 0\n"
    295                 "sync\n"
    296                
    297                 ".rept 64\n"
    298                 "       tlbie %[index]\n"
    299                 "       addi %[index], %[index], 0x1000\n"
    300                 ".endr\n"
    301                
    30295                "eieio\n"
    30396                "tlbsync\n"
    30497                "sync\n"
    305                 : [index] "=r" (index)
    30698        );
    30799}
     
    309101void tlb_invalidate_asid(asid_t asid)
    310102{
    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        
    323103        tlb_invalidate_all();
    324104}
     
    326106void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
    327107{
    328         // TODO
    329108        tlb_invalidate_all();
    330109}
Note: See TracChangeset for help on using the changeset viewer.