Ignore:
File:
1 edited

Legend:

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

    r2429e4a r1dbc43f  
    7979 * @param access   Access mode that caused the fault.
    8080 * @param istate   Pointer to interrupted state.
    81  * @param pfrc     Pointer to variable where as_page_fault()
    82  *                 return code will be stored.
    8381 *
    8482 * @return PTE on success, NULL otherwise.
     
    8684 */
    8785static pte_t *find_mapping_and_check(uintptr_t badvaddr, int access,
    88     istate_t *istate, int *pfrc)
     86    istate_t *istate)
    8987{
    9088        entry_hi_t hi;
    9189        hi.value = cp0_entry_hi_read();
    9290       
    93         /*
    94          * Handler cannot succeed if the ASIDs don't match.
    95          */
    96         if (hi.asid != AS->asid) {
    97                 printf("EntryHi.asid=%d, AS->asid=%d\n", hi.asid, AS->asid);
    98                 return NULL;
    99         }
     91        ASSERT(hi.asid == AS->asid);
    10092       
    10193        /*
     
    109101                 */
    110102                return pte;
    111         } else {
    112                 int rc;
    113                
    114                 /*
    115                  * Mapping not found in page tables.
    116                  * Resort to higher-level page fault handler.
    117                  */
    118                 switch (rc = as_page_fault(badvaddr, access, istate)) {
    119                 case AS_PF_OK:
    120                         /*
    121                          * The higher-level page fault handler succeeded,
    122                          * The mapping ought to be in place.
    123                          */
    124                         pte = page_mapping_find(AS, badvaddr, true);
    125                         ASSERT(pte);
    126                         ASSERT(pte->p);
    127                         ASSERT((pte->w) || (access != PF_ACCESS_WRITE));
    128                         return pte;
    129                 case AS_PF_DEFER:
    130                         *pfrc = AS_PF_DEFER;
    131                         return NULL;
    132                 case AS_PF_FAULT:
    133                         *pfrc = AS_PF_FAULT;
    134                         return NULL;
    135                 default:
    136                         panic("Unexpected return code (%d).", rc);
    137                 }
    138         }
     103        }
     104
     105        /*
     106         * Mapping not found in page tables.
     107         * Resort to higher-level page fault handler.
     108         */
     109        if (as_page_fault(badvaddr, access, istate) == AS_PF_OK) {
     110                /*
     111                 * The higher-level page fault handler succeeded,
     112                 * The mapping ought to be in place.
     113                 */
     114                pte = page_mapping_find(AS, badvaddr, true);
     115                ASSERT(pte);
     116                ASSERT(pte->p);
     117                ASSERT((pte->w) || (access != PF_ACCESS_WRITE));
     118                return pte;
     119        }
     120
     121        return NULL;
    139122}
    140123
     
    156139}
    157140
    158 static void tlb_refill_fail(istate_t *istate)
    159 {
    160         uintptr_t va = cp0_badvaddr_read();
    161        
    162         fault_if_from_uspace(istate, "TLB Refill Exception on %p.",
    163             (void *) va);
    164         panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Refill Exception.");
    165 }
    166 
    167 static void tlb_invalid_fail(istate_t *istate)
    168 {
    169         uintptr_t va = cp0_badvaddr_read();
    170        
    171         fault_if_from_uspace(istate, "TLB Invalid Exception on %p.",
    172             (void *) va);
    173         panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Invalid Exception.");
    174 }
    175 
    176 static void tlb_modified_fail(istate_t *istate)
    177 {
    178         uintptr_t va = cp0_badvaddr_read();
    179        
    180         fault_if_from_uspace(istate, "TLB Modified Exception on %p.",
    181             (void *) va);
    182         panic_memtrap(istate, PF_ACCESS_WRITE, va, "TLB Modified Exception.");
    183 }
    184 
    185141/** Process TLB Refill Exception.
    186142 *
     
    196152        mutex_unlock(&AS->lock);
    197153       
    198         int pfrc;
    199         pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ,
    200             istate, &pfrc);
    201         if (!pte) {
    202                 switch (pfrc) {
    203                 case AS_PF_FAULT:
    204                         goto fail;
    205                         break;
    206                 case AS_PF_DEFER:
    207                         /*
    208                          * The page fault came during copy_from_uspace()
    209                          * or copy_to_uspace().
    210                          */
    211                         return;
    212                 default:
    213                         panic("Unexpected pfrc (%d).", pfrc);
     154        pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
     155        if (pte) {
     156                /*
     157                 * Record access to PTE.
     158                 */
     159                pte->a = 1;
     160       
     161                entry_lo_t lo;
     162                entry_hi_t hi;
     163       
     164                tlb_prepare_entry_hi(&hi, asid, badvaddr);
     165                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->c,
     166                    pte->frame);
     167       
     168                /*
     169                 * New entry is to be inserted into TLB
     170                 */
     171                cp0_entry_hi_write(hi.value);
     172       
     173                if ((badvaddr / PAGE_SIZE) % 2 == 0) {
     174                        cp0_entry_lo0_write(lo.value);
     175                        cp0_entry_lo1_write(0);
     176                } else {
     177                        cp0_entry_lo0_write(0);
     178                        cp0_entry_lo1_write(lo.value);
    214179                }
    215         }
    216        
    217         /*
    218          * Record access to PTE.
    219          */
    220         pte->a = 1;
    221        
    222         entry_lo_t lo;
    223         entry_hi_t hi;
    224        
    225         tlb_prepare_entry_hi(&hi, asid, badvaddr);
    226         tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->c,
    227             pte->frame);
    228        
    229         /*
    230          * New entry is to be inserted into TLB
    231          */
    232         cp0_entry_hi_write(hi.value);
    233        
    234         if ((badvaddr / PAGE_SIZE) % 2 == 0) {
    235                 cp0_entry_lo0_write(lo.value);
    236                 cp0_entry_lo1_write(0);
    237         } else {
    238                 cp0_entry_lo0_write(0);
    239                 cp0_entry_lo1_write(lo.value);
    240         }
    241        
    242         cp0_pagemask_write(TLB_PAGE_MASK_16K);
    243         tlbwr();
    244        
    245         return;
    246        
    247 fail:
    248         tlb_refill_fail(istate);
     180       
     181                cp0_pagemask_write(TLB_PAGE_MASK_16K);
     182                tlbwr();
     183        }
    249184}
    250185
     
    271206        index.value = cp0_index_read();
    272207       
    273         /*
    274          * Fail if the entry is not in TLB.
    275          */
    276         if (index.p) {
    277                 printf("TLB entry not found.\n");
    278                 goto fail;
    279         }
    280        
    281         int pfrc;
    282         pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ,
    283             istate, &pfrc);
    284         if (!pte) {
    285                 switch (pfrc) {
    286                 case AS_PF_FAULT:
    287                         goto fail;
    288                         break;
    289                 case AS_PF_DEFER:
    290                         /*
    291                          * The page fault came during copy_from_uspace()
    292                          * or copy_to_uspace().
    293                          */
    294                         return;
    295                 default:
    296                         panic("Unexpected pfrc (%d).", pfrc);
    297                 }
    298         }
    299        
    300         /*
    301          * Read the faulting TLB entry.
    302          */
    303         tlbr();
    304        
    305         /*
    306          * Record access to PTE.
    307          */
    308         pte->a = 1;
    309        
    310         entry_lo_t lo;
    311         tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->c,
    312             pte->frame);
    313        
    314         /*
    315          * The entry is to be updated in TLB.
    316          */
    317         if ((badvaddr / PAGE_SIZE) % 2 == 0)
    318                 cp0_entry_lo0_write(lo.value);
    319         else
    320                 cp0_entry_lo1_write(lo.value);
    321        
    322         cp0_pagemask_write(TLB_PAGE_MASK_16K);
    323         tlbwi();
    324        
    325         return;
    326        
    327 fail:
    328         tlb_invalid_fail(istate);
     208        ASSERT(!index.p);
     209       
     210        pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
     211        if (pte) {
     212                /*
     213                 * Read the faulting TLB entry.
     214                 */
     215                tlbr();
     216       
     217                /*
     218                 * Record access to PTE.
     219                 */
     220                pte->a = 1;
     221
     222                entry_lo_t lo;
     223                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->c,
     224                    pte->frame);
     225       
     226                /*
     227                 * The entry is to be updated in TLB.
     228                 */
     229                if ((badvaddr / PAGE_SIZE) % 2 == 0)
     230                        cp0_entry_lo0_write(lo.value);
     231                else
     232                        cp0_entry_lo1_write(lo.value);
     233       
     234                cp0_pagemask_write(TLB_PAGE_MASK_16K);
     235                tlbwi();
     236        }
     237       
    329238}
    330239
     
    351260        index.value = cp0_index_read();
    352261       
    353         /*
    354          * Fail if the entry is not in TLB.
    355          */
    356         if (index.p) {
    357                 printf("TLB entry not found.\n");
    358                 goto fail;
    359         }
    360        
    361         int pfrc;
    362         pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE,
    363             istate, &pfrc);
    364         if (!pte) {
    365                 switch (pfrc) {
    366                 case AS_PF_FAULT:
    367                         goto fail;
    368                         break;
    369                 case AS_PF_DEFER:
    370                         /*
    371                          * The page fault came during copy_from_uspace()
    372                          * or copy_to_uspace().
    373                          */
    374                         return;
    375                 default:
    376                         panic("Unexpected pfrc (%d).", pfrc);
    377                 }
    378         }
    379        
    380         /*
    381          * Read the faulting TLB entry.
    382          */
    383         tlbr();
    384        
    385         /*
    386          * Record access and write to PTE.
    387          */
    388         pte->a = 1;
    389         pte->d = 1;
    390        
    391         entry_lo_t lo;
    392         tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->w, pte->c,
    393             pte->frame);
    394        
    395         /*
    396          * The entry is to be updated in TLB.
    397          */
    398         if ((badvaddr / PAGE_SIZE) % 2 == 0)
    399                 cp0_entry_lo0_write(lo.value);
    400         else
    401                 cp0_entry_lo1_write(lo.value);
    402        
    403         cp0_pagemask_write(TLB_PAGE_MASK_16K);
    404         tlbwi();
    405        
    406         return;
    407        
    408 fail:
    409         tlb_modified_fail(istate);
     262        ASSERT(!index.p);
     263       
     264        pte_t *pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate);
     265        if (pte) {
     266                /*
     267                 * Read the faulting TLB entry.
     268                 */
     269                tlbr();
     270       
     271                /*
     272                 * Record access and write to PTE.
     273                 */
     274                pte->a = 1;
     275                pte->d = 1;
     276       
     277                entry_lo_t lo;
     278                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->w, pte->c,
     279                    pte->frame);
     280       
     281                /*
     282                 * The entry is to be updated in TLB.
     283                 */
     284                if ((badvaddr / PAGE_SIZE) % 2 == 0)
     285                        cp0_entry_lo0_write(lo.value);
     286                else
     287                        cp0_entry_lo1_write(lo.value);
     288       
     289                cp0_pagemask_write(TLB_PAGE_MASK_16K);
     290                tlbwi();
     291        }
    410292}
    411293
Note: See TracChangeset for help on using the changeset viewer.