Ignore:
File:
1 edited

Legend:

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

    r1dbc43f r976c434  
    4848#include <symtab.h>
    4949
    50 static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *);
     50#define VPN_SHIFT       12     
     51#define ADDR2VPN(a)     ((a) >> VPN_SHIFT)
     52#define ADDR2VPN2(a)    (ADDR2VPN((a)) >> 1)
     53#define VPN2ADDR(vpn)   ((vpn) << VPN_SHIFT)
     54#define VPN22ADDR(vpn2) (VPN2ADDR(vpn2) << 1)
     55
     56#define BANK_SELECT_BIT(a)      (((a) >> PAGE_WIDTH) & 1)
     57       
    5158
    5259/** Initialize TLB.
     
    8491{
    8592        entry_lo_t lo;
    86         entry_hi_t hi;
    87         asid_t asid;
    8893        uintptr_t badvaddr;
    8994        pte_t *pte;
    9095       
    9196        badvaddr = cp0_badvaddr_read();
    92         asid = AS->asid;
    93        
    94         pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    95         if (pte) {
     97
     98        pte = page_mapping_find(AS, badvaddr, true);
     99        if (pte && pte->p) {
    96100                /*
    97101                 * Record access to PTE.
     
    99103                pte->a = 1;
    100104
    101                 tlb_prepare_entry_hi(&hi, asid, badvaddr);
    102105                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d,
    103106                    pte->cacheable, pte->pfn);
     
    106109                 * New entry is to be inserted into TLB
    107110                 */
    108                 cp0_entry_hi_write(hi.value);
    109                 if ((badvaddr / PAGE_SIZE) % 2 == 0) {
     111                if (BANK_SELECT_BIT(badvaddr) == 0) {
    110112                        cp0_entry_lo0_write(lo.value);
    111113                        cp0_entry_lo1_write(0);
     
    116118                cp0_pagemask_write(TLB_PAGE_MASK_16K);
    117119                tlbwr();
    118         }
     120                return;
     121        }
     122
     123        (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate);
    119124}
    120125
     
    125130void tlb_invalid(istate_t *istate)
    126131{
     132        entry_lo_t lo;
    127133        tlb_index_t index;
    128134        uintptr_t badvaddr;
    129         entry_lo_t lo;
    130         entry_hi_t hi;
    131135        pte_t *pte;
    132 
    133         badvaddr = cp0_badvaddr_read();
    134136
    135137        /*
    136138         * Locate the faulting entry in TLB.
    137139         */
    138         hi.value = cp0_entry_hi_read();
    139         tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
    140         cp0_entry_hi_write(hi.value);
    141140        tlbp();
    142141        index.value = cp0_index_read();
    143142
     143#if defined(PROCESSOR_4Kc)
     144        /*
     145         * This can happen on a 4Kc when Status.EXL is 1 and there is a TLB miss.
     146         * EXL is 1 when interrupts are disabled. The combination of a TLB miss
     147         * and disabled interrupts is possible in copy_to/from_uspace().
     148         */
     149        if (index.p) {
     150                tlb_refill(istate);
     151                return;
     152        }
     153#endif
     154
    144155        ASSERT(!index.p);
    145156
    146         pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    147         if (pte) {
     157        badvaddr = cp0_badvaddr_read();
     158
     159        pte = page_mapping_find(AS, badvaddr, true);
     160        if (pte && pte->p) {
    148161                /*
    149162                 * Read the faulting TLB entry.
     
    162175                 * The entry is to be updated in TLB.
    163176                 */
    164                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
     177                if (BANK_SELECT_BIT(badvaddr) == 0)
    165178                        cp0_entry_lo0_write(lo.value);
    166179                else
    167180                        cp0_entry_lo1_write(lo.value);
    168                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    169181                tlbwi();
    170         }
     182                return;
     183        }
     184
     185        (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate);
    171186}
    172187
     
    177192void tlb_modified(istate_t *istate)
    178193{
     194        entry_lo_t lo;
    179195        tlb_index_t index;
    180196        uintptr_t badvaddr;
    181         entry_lo_t lo;
    182         entry_hi_t hi;
    183197        pte_t *pte;
    184 
    185         badvaddr = cp0_badvaddr_read();
    186198
    187199        /*
    188200         * Locate the faulting entry in TLB.
    189201         */
    190         hi.value = cp0_entry_hi_read();
    191         tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
    192         cp0_entry_hi_write(hi.value);
    193202        tlbp();
    194203        index.value = cp0_index_read();
     
    199208        ASSERT(!index.p);
    200209
    201         pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate);
    202         if (pte) {
     210        badvaddr = cp0_badvaddr_read();
     211
     212        pte = page_mapping_find(AS, badvaddr, true);
     213        if (pte && pte->p && pte->w) {
    203214                /*
    204215                 * Read the faulting TLB entry.
     
    218229                 * The entry is to be updated in TLB.
    219230                 */
    220                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
     231                if (BANK_SELECT_BIT(badvaddr) == 0)
    221232                        cp0_entry_lo0_write(lo.value);
    222233                else
    223234                        cp0_entry_lo1_write(lo.value);
    224                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    225235                tlbwi();
    226         }
    227 }
    228 
    229 /** Try to find PTE for faulting address.
    230  *
    231  * @param badvaddr      Faulting virtual address.
    232  * @param access        Access mode that caused the fault.
    233  * @param istate        Pointer to interrupted state.
    234  *
    235  * @return              PTE on success, NULL otherwise.
    236  */
    237 pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate)
    238 {
    239         entry_hi_t hi;
    240         pte_t *pte;
    241 
    242         hi.value = cp0_entry_hi_read();
    243 
    244         ASSERT(hi.asid == AS->asid);
    245 
    246         /*
    247          * Check if the mapping exists in page tables.
    248          */     
    249         pte = page_mapping_find(AS, badvaddr, true);
    250         if (pte && pte->p && (pte->w || access != PF_ACCESS_WRITE)) {
    251                 /*
    252                  * Mapping found in page tables.
    253                  * Immediately succeed.
    254                  */
    255                 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;
     236                return;
     237        }
     238
     239        (void) as_page_fault(badvaddr, PF_ACCESS_WRITE, istate);
    270240}
    271241
     
    284254void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr)
    285255{
    286         hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2);
     256        hi->value = 0;
     257        hi->vpn2 = ADDR2VPN2(ALIGN_DOWN(addr, PAGE_SIZE));
    287258        hi->asid = asid;
    288259}
     
    291262void tlb_print(void)
    292263{
    293         page_mask_t mask;
    294         entry_lo_t lo0, lo1;
     264        page_mask_t mask, mask_save;
     265        entry_lo_t lo0, lo0_save, lo1, lo1_save;
    295266        entry_hi_t hi, hi_save;
    296267        unsigned int i;
    297268
    298269        hi_save.value = cp0_entry_hi_read();
    299        
    300         printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n");
     270        lo0_save.value = cp0_entry_lo0_read();
     271        lo1_save.value = cp0_entry_lo1_read();
     272        mask_save.value = cp0_pagemask_read();
     273       
     274        printf("[nr] [asid] [vpn2    ] [mask] [gvdc] [pfn     ]\n");
    301275       
    302276        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    309283                lo1.value = cp0_entry_lo1_read();
    310284               
    311                 printf("%-4u %-6u %#6x %#6x  %1u%1u%1u%1u  %#6x\n",
    312                     i, hi.asid, hi.vpn2, mask.mask,
    313                     lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn);
    314                 printf("                           %1u%1u%1u%1u  %#6x\n",
    315                     lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn);
     285                printf("%-4u %-6u %0#10x %-#6x  %1u%1u%1u%1u  %0#10x\n",
     286                    i, hi.asid, VPN22ADDR(hi.vpn2), mask.mask,
     287                    lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn << FRAME_WIDTH);
     288                printf("                               %1u%1u%1u%1u  %0#10x\n",
     289                    lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn << FRAME_WIDTH);
    316290        }
    317291       
    318292        cp0_entry_hi_write(hi_save.value);
     293        cp0_entry_lo0_write(lo0_save.value);
     294        cp0_entry_lo1_write(lo1_save.value);
     295        cp0_pagemask_write(mask_save.value);
    319296}
    320297
     
    322299void tlb_invalidate_all(void)
    323300{
    324         ipl_t ipl;
    325301        entry_lo_t lo0, lo1;
    326302        entry_hi_t hi_save;
    327303        int i;
    328304
     305        ASSERT(interrupts_disabled());
     306
    329307        hi_save.value = cp0_entry_hi_read();
    330         ipl = interrupts_disable();
    331308
    332309        for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) {
     
    346323        }
    347324       
    348         interrupts_restore(ipl);
    349325        cp0_entry_hi_write(hi_save.value);
    350326}
     
    356332void tlb_invalidate_asid(asid_t asid)
    357333{
    358         ipl_t ipl;
    359334        entry_lo_t lo0, lo1;
    360335        entry_hi_t hi, hi_save;
    361336        int i;
    362337
     338        ASSERT(interrupts_disabled());
    363339        ASSERT(asid != ASID_INVALID);
    364340
    365341        hi_save.value = cp0_entry_hi_read();
    366         ipl = interrupts_disable();
    367342       
    368343        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    386361        }
    387362       
    388         interrupts_restore(ipl);
    389363        cp0_entry_hi_write(hi_save.value);
    390364}
     
    400374{
    401375        unsigned int i;
    402         ipl_t ipl;
    403376        entry_lo_t lo0, lo1;
    404377        entry_hi_t hi, hi_save;
    405378        tlb_index_t index;
     379
     380        ASSERT(interrupts_disabled());
    406381       
    407382        if (asid == ASID_INVALID)
     
    409384
    410385        hi_save.value = cp0_entry_hi_read();
    411         ipl = interrupts_disable();
    412386
    413387        for (i = 0; i < cnt + 1; i += 2) {
    414                 hi.value = 0;
    415388                tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE);
    416389                cp0_entry_hi_write(hi.value);
     
    439412        }
    440413       
    441         interrupts_restore(ipl);
    442414        cp0_entry_hi_write(hi_save.value);
    443415}
Note: See TracChangeset for help on using the changeset viewer.