Changeset df3c6f02 in mainline for kernel/arch/ppc32/src/mm/tlb.c


Ignore:
Timestamp:
2011-05-31T22:58:56Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d362410
Parents:
82582e4 (diff), 4ce90544 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    r82582e4 rdf3c6f02  
    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>
     37#include <typedefs.h>
    4538
    46 static unsigned int seed = 10;
    47 static 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  */
    63 static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access,
    64     istate_t *istate, int *pfrc)
     39void tlb_refill(unsigned int n, istate_t *istate)
    6540{
    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 
    111 static 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 
    119 static 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;
     41        uint32_t tlbmiss;
     42        ptehi_t ptehi;
     43        ptelo_t ptelo;
    12344       
    124         uint32_t vsid = sr_get(vaddr);
    125         uint32_t sdr1 = sdr1_get();
     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        );
    12653       
    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  */
    208 void 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        
    248 fail:
    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  */
    259 bool 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  */
    365 void tlb_refill_real(unsigned int n, uint32_t tlbmiss, ptehi_t ptehi,
    366     ptelo_t ptelo, istate_t *istate)
    367 {
    36854        uint32_t badvaddr = tlbmiss & 0xfffffffc;
    36955        uint32_t physmem = physmem_top();
     
    39581void tlb_invalidate_all(void)
    39682{
    397         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        }
    39893       
    39994        asm volatile (
    400                 "li %[index], 0\n"
    401                 "sync\n"
    402                
    403                 ".rept 64\n"
    404                 "       tlbie %[index]\n"
    405                 "       addi %[index], %[index], 0x1000\n"
    406                 ".endr\n"
    407                
    40895                "eieio\n"
    40996                "tlbsync\n"
    41097                "sync\n"
    411                 : [index] "=r" (index)
    41298        );
    41399}
     
    415101void tlb_invalidate_asid(asid_t asid)
    416102{
    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        
    429103        tlb_invalidate_all();
    430104}
     
    432106void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
    433107{
    434         // TODO
    435108        tlb_invalidate_all();
    436109}
Note: See TracChangeset for help on using the changeset viewer.