Changeset 38a1a84 in mainline for arch/mips32/src/mm/tlb.c


Ignore:
Timestamp:
2005-10-05T21:29:16Z (20 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bca1b47
Parents:
49c1f93
Message:

MIPS32 memory management work.
Fix some bugs introduced yesterday (PTL3 index is indeed calculated by >> 14).
Introduce two new bits in pte_t (i.e. 'a' and 'w').
Implement TLB Invalid Exception and TLB Modified Exception. (Needs review and testing)

File:
1 edited

Legend:

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

    r49c1f93 r38a1a84  
    4343static void tlb_modified_fail(struct exception_regdump *pstate);
    4444
     45static pte_t *find_mapping_and_check(__address badvaddr);
     46static void prepare_entry_lo(struct entry_lo *lo, bool g, bool v, bool d, bool c, __address pfn);
     47
    4548/** Initialize TLB
    4649 *
     
    8083void tlb_refill(struct exception_regdump *pstate)
    8184{
    82         struct entry_hi hi;
     85        struct entry_lo lo;
    8386        __address badvaddr;
    8487        pte_t *pte;
    8588       
    86         *((__u32 *) &hi) = cp0_entry_hi_read();
    8789        badvaddr = cp0_badvaddr_read();
    8890       
    89         spinlock_lock(&VM->lock);
    90 
    91         /*
    92          * Refill cannot succeed if the ASIDs don't match.
    93          */
    94         if (hi.asid != VM->asid)
    95                 goto fail;
    96 
    97         /*
    98          * Refill cannot succeed if badvaddr is not
    99          * associated with any mapping.
    100          */
    101         pte = find_mapping(badvaddr, 0);
     91        spinlock_lock(&VM->lock);               
     92        pte = find_mapping_and_check(badvaddr);
    10293        if (!pte)
    10394                goto fail;
    104                
    105         /*
    106          * Refill cannot succeed if the mapping is marked as invalid.
    107          */
    108         if (!pte->v)
    109                 goto fail;
     95
     96        /*
     97         * Record access to PTE.
     98         */
     99        pte->a = 1;
     100
     101        prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
    110102
    111103        /*
    112104         * New entry is to be inserted into TLB
    113105         */
    114         cp0_pagemask_write(TLB_PAGE_MASK_16K);
    115106        if ((badvaddr/PAGE_SIZE) % 2 == 0) {
    116                 cp0_entry_lo0_write(*((__u32 *) pte));
     107                cp0_entry_lo0_write(*((__u32 *) &lo));
    117108                cp0_entry_lo1_write(0);
    118109        }
    119110        else {
    120111                cp0_entry_lo0_write(0);
    121                 cp0_entry_lo1_write(*((__u32 *) pte));
     112                cp0_entry_lo1_write(*((__u32 *) &lo));
    122113        }
    123114        tlbwr();
     
    131122}
    132123
     124/** Process TLB Invalid Exception
     125 *
     126 * Process TLB Invalid Exception.
     127 *
     128 * @param pstate Interrupted register context.
     129 */
    133130void tlb_invalid(struct exception_regdump *pstate)
    134131{
     132        struct index index;
     133        __address badvaddr;
     134        struct entry_lo lo;
     135        pte_t *pte;
     136
     137        badvaddr = cp0_badvaddr_read();
     138
     139        /*
     140         * Locate the faulting entry in TLB.
     141         */
     142        tlbp();
     143        *((__u32 *) &index) = cp0_index_read();
     144       
     145        spinlock_lock(&VM->lock);       
     146       
     147        /*
     148         * Fail if the entry is not in TLB.
     149         */
     150        if (index.p)
     151                goto fail;
     152
     153        pte = find_mapping_and_check(badvaddr);
     154        if (!pte)
     155                goto fail;
     156
     157        /*
     158         * Read the faulting TLB entry.
     159         */
     160        tlbr();
     161
     162        /*
     163         * Record access to PTE.
     164         */
     165        pte->a = 1;
     166
     167        prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
     168
     169        /*
     170         * The entry is to be updated in TLB.
     171         */
     172        if ((badvaddr/PAGE_SIZE) % 2 == 0)
     173                cp0_entry_lo0_write(*((__u32 *) &lo));
     174        else
     175                cp0_entry_lo1_write(*((__u32 *) &lo));
     176        tlbwi();
     177
     178        spinlock_unlock(&VM->lock);     
     179        return;
     180       
     181fail:
     182        spinlock_unlock(&VM->lock);
    135183        tlb_invalid_fail(pstate);
    136184}
    137185
     186/** Process TLB Modified Exception
     187 *
     188 * Process TLB Modified Exception.
     189 *
     190 * @param pstate Interrupted register context.
     191 */
     192
    138193void tlb_modified(struct exception_regdump *pstate)
    139194{
     195        struct index index;
     196        __address badvaddr;
     197        struct entry_lo lo;
     198        pte_t *pte;
     199
     200        badvaddr = cp0_badvaddr_read();
     201
     202        /*
     203         * Locate the faulting entry in TLB.
     204         */
     205        tlbp();
     206        *((__u32 *) &index) = cp0_index_read();
     207       
     208        spinlock_lock(&VM->lock);       
     209       
     210        /*
     211         * Fail if the entry is not in TLB.
     212         */
     213        if (index.p)
     214                goto fail;
     215
     216        pte = find_mapping_and_check(badvaddr);
     217        if (!pte)
     218                goto fail;
     219
     220        /*
     221         * Fail if the page is not writable.
     222         */
     223        if (!pte->w)
     224                goto fail;
     225
     226        /*
     227         * Read the faulting TLB entry.
     228         */
     229        tlbr();
     230
     231        /*
     232         * Record access and write to PTE.
     233         */
     234        pte->a = 1;
     235        pte->d = 1;
     236
     237        prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
     238
     239        /*
     240         * The entry is to be updated in TLB.
     241         */
     242        if ((badvaddr/PAGE_SIZE) % 2 == 0)
     243                cp0_entry_lo0_write(*((__u32 *) &lo));
     244        else
     245                cp0_entry_lo1_write(*((__u32 *) &lo));
     246        tlbwi();
     247
     248        spinlock_unlock(&VM->lock);     
     249        return;
     250       
     251fail:
     252        spinlock_unlock(&VM->lock);
    140253        tlb_modified_fail(pstate);
    141254}
     
    163276        if (s)
    164277                symbol = s;
    165         panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(),
    166               pstate->epc, symbol);
     278        panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
    167279}
    168280
     
    174286        if (s)
    175287                symbol = s;
    176         panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(),
    177               pstate->epc, symbol);
     288        panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
    178289}
    179290
     
    189300        cpu_priority_restore(pri);
    190301}
     302
     303/** Try to find PTE for faulting address
     304 *
     305 * Try to find PTE for faulting address.
     306 * The VM->lock must be held on entry to this function.
     307 *
     308 * @param badvaddr Faulting virtual address.
     309 *
     310 * @return PTE on success, NULL otherwise.
     311 */
     312pte_t *find_mapping_and_check(__address badvaddr)
     313{
     314        struct entry_hi hi;
     315        pte_t *pte;
     316
     317        *((__u32 *) &hi) = cp0_entry_hi_read();
     318
     319        /*
     320         * Handler cannot succeed if the ASIDs don't match.
     321         */
     322        if (hi.asid != VM->asid)
     323                return NULL;
     324       
     325        /*
     326         * Handler cannot succeed if badvaddr has no mapping.
     327         */
     328        pte = find_mapping(badvaddr, 0);
     329        if (!pte)
     330                return NULL;
     331
     332        /*
     333         * Handler cannot succeed if the mapping is marked as invalid.
     334         */
     335        if (!pte->v)
     336                return NULL;
     337
     338        return pte;
     339}
     340
     341void prepare_entry_lo(struct entry_lo *lo, bool g, bool v, bool d, bool c, __address pfn)
     342{
     343        lo->g = g;
     344        lo->v = v;
     345        lo->d = d;
     346        lo->c = c;
     347        lo->pfn = pfn;
     348        lo->zero = 0;
     349}
Note: See TracChangeset for help on using the changeset viewer.