Changeset 1dbc43f in mainline for kernel/arch/mips32/src/mm/tlb.c


Ignore:
Timestamp:
2012-11-22T21:23:47Z (12 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
908bb96
Parents:
34ae0a5
Message:

Unify user page fault handling in as_page_fault().

  • Remove lots of architecture-dependent boilerplate code.
File:
1 edited

Legend:

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

    r34ae0a5 r1dbc43f  
    4848#include <symtab.h>
    4949
    50 static void tlb_refill_fail(istate_t *);
    51 static void tlb_invalid_fail(istate_t *);
    52 static void tlb_modified_fail(istate_t *);
    53 
    54 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *, int *);
     50static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *);
    5551
    5652/** Initialize TLB.
     
    9288        uintptr_t badvaddr;
    9389        pte_t *pte;
    94         int pfrc;
    9590       
    9691        badvaddr = cp0_badvaddr_read();
    9792        asid = AS->asid;
    9893       
    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);
     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);
    113115                }
    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        
    142 fail:
    143         tlb_refill_fail(istate);
     116                cp0_pagemask_write(TLB_PAGE_MASK_16K);
     117                tlbwr();
     118        }
    144119}
    145120
     
    155130        entry_hi_t hi;
    156131        pte_t *pte;
    157         int pfrc;
    158132
    159133        badvaddr = cp0_badvaddr_read();
     
    168142        index.value = cp0_index_read();
    169143
    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        
    220 fail:
    221         tlb_invalid_fail(istate);
     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        }
    222171}
    223172
     
    233182        entry_hi_t hi;
    234183        pte_t *pte;
    235         int pfrc;
    236184
    237185        badvaddr = cp0_badvaddr_read();
     
    249197         * Fail if the entry is not in TLB.
    250198         */
    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        
    299 fail:
    300         tlb_modified_fail(istate);
    301 }
    302 
    303 void 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 
    313 void 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 
    322 void 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.");
     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        }
    329227}
    330228
     
    334232 * @param access        Access mode that caused the fault.
    335233 * @param istate        Pointer to interrupted state.
    336  * @param pfrc          Pointer to variable where as_page_fault() return code
    337  *                      will be stored.
    338234 *
    339235 * @return              PTE on success, NULL otherwise.
    340236 */
    341 pte_t *
    342 find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate,
    343     int *pfrc)
     237pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate)
    344238{
    345239        entry_hi_t hi;
     
    348242        hi.value = cp0_entry_hi_read();
    349243
    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         }
     244        ASSERT(hi.asid == AS->asid);
    357245
    358246        /*
     
    366254                 */
    367255                return pte;
    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         }
     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;
    396270}
    397271
Note: See TracChangeset for help on using the changeset viewer.