Ignore:
File:
1 edited

Legend:

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

    r976c434 r1dbc43f  
    4848#include <symtab.h>
    4949
    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        
     50static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *);
    5851
    5952/** Initialize TLB.
     
    9184{
    9285        entry_lo_t lo;
     86        entry_hi_t hi;
     87        asid_t asid;
    9388        uintptr_t badvaddr;
    9489        pte_t *pte;
    9590       
    9691        badvaddr = cp0_badvaddr_read();
    97 
    98         pte = page_mapping_find(AS, badvaddr, true);
    99         if (pte && pte->p) {
     92        asid = AS->asid;
     93       
     94        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
     95        if (pte) {
    10096                /*
    10197                 * Record access to PTE.
     
    10399                pte->a = 1;
    104100
     101                tlb_prepare_entry_hi(&hi, asid, badvaddr);
    105102                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d,
    106103                    pte->cacheable, pte->pfn);
     
    109106                 * New entry is to be inserted into TLB
    110107                 */
    111                 if (BANK_SELECT_BIT(badvaddr) == 0) {
     108                cp0_entry_hi_write(hi.value);
     109                if ((badvaddr / PAGE_SIZE) % 2 == 0) {
    112110                        cp0_entry_lo0_write(lo.value);
    113111                        cp0_entry_lo1_write(0);
     
    118116                cp0_pagemask_write(TLB_PAGE_MASK_16K);
    119117                tlbwr();
    120                 return;
    121         }
    122 
    123         (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate);
     118        }
    124119}
    125120
     
    130125void tlb_invalid(istate_t *istate)
    131126{
    132         entry_lo_t lo;
    133127        tlb_index_t index;
    134128        uintptr_t badvaddr;
     129        entry_lo_t lo;
     130        entry_hi_t hi;
    135131        pte_t *pte;
     132
     133        badvaddr = cp0_badvaddr_read();
    136134
    137135        /*
    138136         * Locate the faulting entry in TLB.
    139137         */
     138        hi.value = cp0_entry_hi_read();
     139        tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
     140        cp0_entry_hi_write(hi.value);
    140141        tlbp();
    141142        index.value = cp0_index_read();
    142143
    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 
    155144        ASSERT(!index.p);
    156145
    157         badvaddr = cp0_badvaddr_read();
    158 
    159         pte = page_mapping_find(AS, badvaddr, true);
    160         if (pte && pte->p) {
     146        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
     147        if (pte) {
    161148                /*
    162149                 * Read the faulting TLB entry.
     
    175162                 * The entry is to be updated in TLB.
    176163                 */
    177                 if (BANK_SELECT_BIT(badvaddr) == 0)
     164                if ((badvaddr / PAGE_SIZE) % 2 == 0)
    178165                        cp0_entry_lo0_write(lo.value);
    179166                else
    180167                        cp0_entry_lo1_write(lo.value);
     168                cp0_pagemask_write(TLB_PAGE_MASK_16K);
    181169                tlbwi();
    182                 return;
    183         }
    184 
    185         (void) as_page_fault(badvaddr, PF_ACCESS_READ, istate);
     170        }
    186171}
    187172
     
    192177void tlb_modified(istate_t *istate)
    193178{
    194         entry_lo_t lo;
    195179        tlb_index_t index;
    196180        uintptr_t badvaddr;
     181        entry_lo_t lo;
     182        entry_hi_t hi;
    197183        pte_t *pte;
     184
     185        badvaddr = cp0_badvaddr_read();
    198186
    199187        /*
    200188         * Locate the faulting entry in TLB.
    201189         */
     190        hi.value = cp0_entry_hi_read();
     191        tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
     192        cp0_entry_hi_write(hi.value);
    202193        tlbp();
    203194        index.value = cp0_index_read();
     
    208199        ASSERT(!index.p);
    209200
    210         badvaddr = cp0_badvaddr_read();
    211 
    212         pte = page_mapping_find(AS, badvaddr, true);
    213         if (pte && pte->p && pte->w) {
     201        pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate);
     202        if (pte) {
    214203                /*
    215204                 * Read the faulting TLB entry.
     
    229218                 * The entry is to be updated in TLB.
    230219                 */
    231                 if (BANK_SELECT_BIT(badvaddr) == 0)
     220                if ((badvaddr / PAGE_SIZE) % 2 == 0)
    232221                        cp0_entry_lo0_write(lo.value);
    233222                else
    234223                        cp0_entry_lo1_write(lo.value);
     224                cp0_pagemask_write(TLB_PAGE_MASK_16K);
    235225                tlbwi();
    236                 return;
    237         }
    238 
    239         (void) as_page_fault(badvaddr, PF_ACCESS_WRITE, istate);
     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 */
     237pte_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;
    240270}
    241271
     
    254284void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr)
    255285{
    256         hi->value = 0;
    257         hi->vpn2 = ADDR2VPN2(ALIGN_DOWN(addr, PAGE_SIZE));
     286        hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2);
    258287        hi->asid = asid;
    259288}
     
    262291void tlb_print(void)
    263292{
    264         page_mask_t mask, mask_save;
    265         entry_lo_t lo0, lo0_save, lo1, lo1_save;
     293        page_mask_t mask;
     294        entry_lo_t lo0, lo1;
    266295        entry_hi_t hi, hi_save;
    267296        unsigned int i;
    268297
    269298        hi_save.value = cp0_entry_hi_read();
    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");
     299       
     300        printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n");
    275301       
    276302        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    283309                lo1.value = cp0_entry_lo1_read();
    284310               
    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);
     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);
    290316        }
    291317       
    292318        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);
    296319}
    297320
     
    299322void tlb_invalidate_all(void)
    300323{
     324        ipl_t ipl;
    301325        entry_lo_t lo0, lo1;
    302326        entry_hi_t hi_save;
    303327        int i;
    304328
    305         ASSERT(interrupts_disabled());
    306 
    307329        hi_save.value = cp0_entry_hi_read();
     330        ipl = interrupts_disable();
    308331
    309332        for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) {
     
    323346        }
    324347       
     348        interrupts_restore(ipl);
    325349        cp0_entry_hi_write(hi_save.value);
    326350}
     
    332356void tlb_invalidate_asid(asid_t asid)
    333357{
     358        ipl_t ipl;
    334359        entry_lo_t lo0, lo1;
    335360        entry_hi_t hi, hi_save;
    336361        int i;
    337362
    338         ASSERT(interrupts_disabled());
    339363        ASSERT(asid != ASID_INVALID);
    340364
    341365        hi_save.value = cp0_entry_hi_read();
     366        ipl = interrupts_disable();
    342367       
    343368        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    361386        }
    362387       
     388        interrupts_restore(ipl);
    363389        cp0_entry_hi_write(hi_save.value);
    364390}
     
    374400{
    375401        unsigned int i;
     402        ipl_t ipl;
    376403        entry_lo_t lo0, lo1;
    377404        entry_hi_t hi, hi_save;
    378405        tlb_index_t index;
    379 
    380         ASSERT(interrupts_disabled());
    381406       
    382407        if (asid == ASID_INVALID)
     
    384409
    385410        hi_save.value = cp0_entry_hi_read();
     411        ipl = interrupts_disable();
    386412
    387413        for (i = 0; i < cnt + 1; i += 2) {
     414                hi.value = 0;
    388415                tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE);
    389416                cp0_entry_hi_write(hi.value);
     
    412439        }
    413440       
     441        interrupts_restore(ipl);
    414442        cp0_entry_hi_write(hi_save.value);
    415443}
Note: See TracChangeset for help on using the changeset viewer.