Ignore:
File:
1 edited

Legend:

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

    r1dbc43f r9d58539  
    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.
    8183 *
    8284 * @return PTE on success, NULL otherwise.
     
    8486 */
    8587static pte_t *find_mapping_and_check(uintptr_t badvaddr, int access,
    86     istate_t *istate)
     88    istate_t *istate, int *pfrc)
    8789{
    8890        entry_hi_t hi;
    8991        hi.value = cp0_entry_hi_read();
    9092       
    91         ASSERT(hi.asid == AS->asid);
     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        }
    92100       
    93101        /*
     
    101109                 */
    102110                return pte;
    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) {
     111        } else {
     112                int rc;
     113               
    110114                /*
    111                  * The higher-level page fault handler succeeded,
    112                  * The mapping ought to be in place.
     115                 * Mapping not found in page tables.
     116                 * Resort to higher-level page fault handler.
    113117                 */
    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;
     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        }
    122139}
    123140
     
    139156}
    140157
     158static 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
     167static 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
     176static 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
    141185/** Process TLB Refill Exception.
    142186 *
     
    152196        mutex_unlock(&AS->lock);
    153197       
    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);
     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);
    179214                }
    180        
    181                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    182                 tlbwr();
    183         }
     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       
     247fail:
     248        tlb_refill_fail(istate);
    184249}
    185250
     
    206271        index.value = cp0_index_read();
    207272       
    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        
     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       
     327fail:
     328        tlb_invalid_fail(istate);
    238329}
    239330
     
    260351        index.value = cp0_index_read();
    261352       
    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         }
     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       
     408fail:
     409        tlb_modified_fail(istate);
    292410}
    293411
Note: See TracChangeset for help on using the changeset viewer.