Ignore:
File:
1 edited

Legend:

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

    r1dbc43f r9d58539  
    4848#include <symtab.h>
    4949
    50 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *);
     50static void tlb_refill_fail(istate_t *);
     51static void tlb_invalid_fail(istate_t *);
     52static void tlb_modified_fail(istate_t *);
     53
     54static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *, int *);
    5155
    5256/** Initialize TLB.
     
    8892        uintptr_t badvaddr;
    8993        pte_t *pte;
     94        int pfrc;
    9095       
    9196        badvaddr = cp0_badvaddr_read();
    9297        asid = AS->asid;
    9398       
    94         pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    95         if (pte) {
    96                 /*
    97                  * Record access to PTE.
    98                  */
    99                 pte->a = 1;
    100 
    101                 tlb_prepare_entry_hi(&hi, asid, badvaddr);
    102                 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d,
    103                     pte->cacheable, pte->pfn);
    104 
    105                 /*
    106                  * New entry is to be inserted into TLB
    107                  */
    108                 cp0_entry_hi_write(hi.value);
    109                 if ((badvaddr / PAGE_SIZE) % 2 == 0) {
    110                         cp0_entry_lo0_write(lo.value);
    111                         cp0_entry_lo1_write(0);
    112                 } else {
    113                         cp0_entry_lo0_write(0);
    114                         cp0_entry_lo1_write(lo.value);
     99        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate, &pfrc);
     100        if (!pte) {
     101                switch (pfrc) {
     102                case AS_PF_FAULT:
     103                        goto fail;
     104                        break;
     105                case AS_PF_DEFER:
     106                        /*
     107                         * The page fault came during copy_from_uspace()
     108                         * or copy_to_uspace().
     109                         */
     110                        return;
     111                default:
     112                        panic("Unexpected pfrc (%d).", pfrc);
    115113                }
    116                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    117                 tlbwr();
    118         }
     114        }
     115
     116        /*
     117         * Record access to PTE.
     118         */
     119        pte->a = 1;
     120
     121        tlb_prepare_entry_hi(&hi, asid, badvaddr);
     122        tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->cacheable,
     123            pte->pfn);
     124
     125        /*
     126         * New entry is to be inserted into TLB
     127         */
     128        cp0_entry_hi_write(hi.value);
     129        if ((badvaddr / PAGE_SIZE) % 2 == 0) {
     130                cp0_entry_lo0_write(lo.value);
     131                cp0_entry_lo1_write(0);
     132        }
     133        else {
     134                cp0_entry_lo0_write(0);
     135                cp0_entry_lo1_write(lo.value);
     136        }
     137        cp0_pagemask_write(TLB_PAGE_MASK_16K);
     138        tlbwr();
     139
     140        return;
     141       
     142fail:
     143        tlb_refill_fail(istate);
    119144}
    120145
     
    130155        entry_hi_t hi;
    131156        pte_t *pte;
     157        int pfrc;
    132158
    133159        badvaddr = cp0_badvaddr_read();
     
    142168        index.value = cp0_index_read();
    143169
    144         ASSERT(!index.p);
    145 
    146         pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    147         if (pte) {
    148                 /*
    149                  * Read the faulting TLB entry.
    150                  */
    151                 tlbr();
    152 
    153                 /*
    154                  * Record access to PTE.
    155                  */
    156                 pte->a = 1;
    157 
    158                 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d,
    159                     pte->cacheable, pte->pfn);
    160 
    161                 /*
    162                  * The entry is to be updated in TLB.
    163                  */
    164                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
    165                         cp0_entry_lo0_write(lo.value);
    166                 else
    167                         cp0_entry_lo1_write(lo.value);
    168                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    169                 tlbwi();
    170         }
     170        /*
     171         * Fail if the entry is not in TLB.
     172         */
     173        if (index.p) {
     174                printf("TLB entry not found.\n");
     175                goto fail;
     176        }
     177
     178        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate, &pfrc);
     179        if (!pte) {
     180                switch (pfrc) {
     181                case AS_PF_FAULT:
     182                        goto fail;
     183                        break;
     184                case AS_PF_DEFER:
     185                        /*
     186                         * The page fault came during copy_from_uspace()
     187                         * or copy_to_uspace().
     188                         */
     189                        return;
     190                default:
     191                        panic("Unexpected pfrc (%d).", pfrc);
     192                }
     193        }
     194
     195        /*
     196         * Read the faulting TLB entry.
     197         */
     198        tlbr();
     199
     200        /*
     201         * Record access to PTE.
     202         */
     203        pte->a = 1;
     204
     205        tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->cacheable,
     206            pte->pfn);
     207
     208        /*
     209         * The entry is to be updated in TLB.
     210         */
     211        if ((badvaddr / PAGE_SIZE) % 2 == 0)
     212                cp0_entry_lo0_write(lo.value);
     213        else
     214                cp0_entry_lo1_write(lo.value);
     215        cp0_pagemask_write(TLB_PAGE_MASK_16K);
     216        tlbwi();
     217
     218        return;
     219       
     220fail:
     221        tlb_invalid_fail(istate);
    171222}
    172223
     
    182233        entry_hi_t hi;
    183234        pte_t *pte;
     235        int pfrc;
    184236
    185237        badvaddr = cp0_badvaddr_read();
     
    197249         * Fail if the entry is not in TLB.
    198250         */
    199         ASSERT(!index.p);
    200 
    201         pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate);
    202         if (pte) {
    203                 /*
    204                  * Read the faulting TLB entry.
    205                  */
    206                 tlbr();
    207 
    208                 /*
    209                  * Record access and write to PTE.
    210                  */
    211                 pte->a = 1;
    212                 pte->d = 1;
    213 
    214                 tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->w,
    215                     pte->cacheable, pte->pfn);
    216 
    217                 /*
    218                  * The entry is to be updated in TLB.
    219                  */
    220                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
    221                         cp0_entry_lo0_write(lo.value);
    222                 else
    223                         cp0_entry_lo1_write(lo.value);
    224                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    225                 tlbwi();
    226         }
     251        if (index.p) {
     252                printf("TLB entry not found.\n");
     253                goto fail;
     254        }
     255
     256        pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate, &pfrc);
     257        if (!pte) {
     258                switch (pfrc) {
     259                case AS_PF_FAULT:
     260                        goto fail;
     261                        break;
     262                case AS_PF_DEFER:
     263                        /*
     264                         * The page fault came during copy_from_uspace()
     265                         * or copy_to_uspace().
     266                         */
     267                        return;
     268                default:
     269                        panic("Unexpected pfrc (%d).", pfrc);
     270                }
     271        }
     272
     273        /*
     274         * Read the faulting TLB entry.
     275         */
     276        tlbr();
     277
     278        /*
     279         * Record access and write to PTE.
     280         */
     281        pte->a = 1;
     282        pte->d = 1;
     283
     284        tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->w, pte->cacheable,
     285            pte->pfn);
     286
     287        /*
     288         * The entry is to be updated in TLB.
     289         */
     290        if ((badvaddr / PAGE_SIZE) % 2 == 0)
     291                cp0_entry_lo0_write(lo.value);
     292        else
     293                cp0_entry_lo1_write(lo.value);
     294        cp0_pagemask_write(TLB_PAGE_MASK_16K);
     295        tlbwi();
     296
     297        return;
     298       
     299fail:
     300        tlb_modified_fail(istate);
     301}
     302
     303void tlb_refill_fail(istate_t *istate)
     304{
     305        uintptr_t va = cp0_badvaddr_read();
     306       
     307        fault_if_from_uspace(istate, "TLB Refill Exception on %p.",
     308            (void *) va);
     309        panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Refill Exception.");
     310}
     311
     312
     313void tlb_invalid_fail(istate_t *istate)
     314{
     315        uintptr_t va = cp0_badvaddr_read();
     316       
     317        fault_if_from_uspace(istate, "TLB Invalid Exception on %p.",
     318            (void *) va);
     319        panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Invalid Exception.");
     320}
     321
     322void tlb_modified_fail(istate_t *istate)
     323{
     324        uintptr_t va = cp0_badvaddr_read();
     325       
     326        fault_if_from_uspace(istate, "TLB Modified Exception on %p.",
     327            (void *) va);
     328        panic_memtrap(istate, PF_ACCESS_WRITE, va, "TLB Modified Exception.");
    227329}
    228330
     
    232334 * @param access        Access mode that caused the fault.
    233335 * @param istate        Pointer to interrupted state.
     336 * @param pfrc          Pointer to variable where as_page_fault() return code
     337 *                      will be stored.
    234338 *
    235339 * @return              PTE on success, NULL otherwise.
    236340 */
    237 pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate)
     341pte_t *
     342find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate,
     343    int *pfrc)
    238344{
    239345        entry_hi_t hi;
     
    242348        hi.value = cp0_entry_hi_read();
    243349
    244         ASSERT(hi.asid == AS->asid);
     350        /*
     351         * Handler cannot succeed if the ASIDs don't match.
     352         */
     353        if (hi.asid != AS->asid) {
     354                printf("EntryHi.asid=%d, AS->asid=%d\n", hi.asid, AS->asid);
     355                return NULL;
     356        }
    245357
    246358        /*
     
    254366                 */
    255367                return pte;
    256         }
    257 
    258         /*
    259          * Mapping not found in page tables.
    260          * Resort to higher-level page fault handler.
    261          */
    262         if (as_page_fault(badvaddr, access, istate) == AS_PF_OK) {
    263                 pte = page_mapping_find(AS, badvaddr, true);
    264                 ASSERT(pte && pte->p);
    265                 ASSERT(pte->w || access != PF_ACCESS_WRITE);
    266                 return pte;
    267         }
    268 
    269         return NULL;
     368        } else {
     369                int rc;
     370               
     371                /*
     372                 * Mapping not found in page tables.
     373                 * Resort to higher-level page fault handler.
     374                 */
     375                switch (rc = as_page_fault(badvaddr, access, istate)) {
     376                case AS_PF_OK:
     377                        /*
     378                         * The higher-level page fault handler succeeded,
     379                         * The mapping ought to be in place.
     380                         */
     381                        pte = page_mapping_find(AS, badvaddr, true);
     382                        ASSERT(pte && pte->p);
     383                        ASSERT(pte->w || access != PF_ACCESS_WRITE);
     384                        return pte;
     385                case AS_PF_DEFER:
     386                        *pfrc = AS_PF_DEFER;
     387                        return NULL;
     388                case AS_PF_FAULT:
     389                        *pfrc = AS_PF_FAULT;
     390                        return NULL;
     391                default:
     392                        panic("Unexpected rc (%d).", rc);
     393                }
     394               
     395        }
    270396}
    271397
Note: See TracChangeset for help on using the changeset viewer.