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


Ignore:
Timestamp:
2013-02-16T23:26:55Z (11 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
192a23f0
Parents:
d5b9e8d
Message:

Improvements of the TLB exception handling.

  • TLBP should be able to use EntryHI right away.
  • TLBR sets EntryHI and PageMask as needed.
  • Make the exception handlers immune against TLB changes while blocking.
  • tlb_print() now preserves the CP0 registers.
  • tlb_print() now prints the full addresses, not just vpn2.
  • Do not disable interrupts in tlb_invalidate_*(), only assert it.
  • Use self-explanatory macros.
File:
1 edited

Legend:

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

    rd5b9e8d re05b956  
    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       
     58
    5059static pte_t *find_mapping_and_check(uintptr_t, int, istate_t *);
    5160
     
    7786}
    7887
     88/** Verify the TLB still contains / does not contain a given entry after the
     89 * current thread possibly blocked.
     90 *
     91 * @param hi           Remembered contents of the EntryHi register.
     92 * @param should_exist Flag saying whether the caller expect the entry to exist
     93 *                     or not to exist.
     94 * @returns            True if the TLB contains or does not contain the mapping
     95 *                     according to the caller's expectation.
     96 * @returns            False otherwise.
     97 */
     98static bool tlb_recheck_entry(entry_hi_t hi, bool should_exist)
     99{
     100        tlb_index_t index;
     101
     102        cp0_entry_hi_write(hi.value);
     103        tlbp();
     104        index.value = cp0_index_read();
     105
     106        if (!(should_exist ^ index.p)) {
     107                /* The old entry disappeared or the new entry already exists. */
     108                return false;
     109        }
     110
     111        return true;
     112}
     113
    79114/** Process TLB Refill Exception.
    80115 *
     
    83118void tlb_refill(istate_t *istate)
    84119{
     120        entry_hi_t hi;
    85121        entry_lo_t lo;
    86         entry_hi_t hi;
    87         asid_t asid;
    88122        uintptr_t badvaddr;
    89123        pte_t *pte;
    90124       
    91125        badvaddr = cp0_badvaddr_read();
    92         asid = AS->asid;
    93        
     126        hi.value = cp0_entry_hi_read();
     127
     128        /* We may block in find_mapping_and_check(). */
    94129        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    95130        if (pte) {
     131                if (!tlb_recheck_entry(hi, false))
     132                        return;
     133
    96134                /*
    97135                 * Record access to PTE.
     
    99137                pte->a = 1;
    100138
    101                 tlb_prepare_entry_hi(&hi, asid, badvaddr);
    102139                tlb_prepare_entry_lo(&lo, pte->g, pte->p, pte->d,
    103140                    pte->cacheable, pte->pfn);
     
    106143                 * New entry is to be inserted into TLB
    107144                 */
    108                 cp0_entry_hi_write(hi.value);
    109                 if ((badvaddr / PAGE_SIZE) % 2 == 0) {
     145                if (BANK_SELECT_BIT(badvaddr) == 0) {
    110146                        cp0_entry_lo0_write(lo.value);
    111147                        cp0_entry_lo1_write(0);
     
    125161void tlb_invalid(istate_t *istate)
    126162{
     163        entry_hi_t hi;
     164        entry_lo_t lo;
    127165        tlb_index_t index;
    128166        uintptr_t badvaddr;
    129         entry_lo_t lo;
    130         entry_hi_t hi;
    131167        pte_t *pte;
    132168
    133         badvaddr = cp0_badvaddr_read();
    134 
    135169        /*
    136170         * Locate the faulting entry in TLB.
    137171         */
    138         hi.value = cp0_entry_hi_read();
    139         tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
    140         cp0_entry_hi_write(hi.value);
    141172        tlbp();
    142173        index.value = cp0_index_read();
     
    156187        ASSERT(!index.p);
    157188
     189        badvaddr = cp0_badvaddr_read();
     190        hi.value = cp0_entry_hi_read();
     191
     192        /* We may block in find_mapping_and_check(). */
    158193        pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate);
    159194        if (pte) {
     195                if (!tlb_recheck_entry(hi, true))
     196                        return;
     197
    160198                /*
    161199                 * Read the faulting TLB entry.
     
    174212                 * The entry is to be updated in TLB.
    175213                 */
    176                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
     214                if (BANK_SELECT_BIT(badvaddr) == 0)
    177215                        cp0_entry_lo0_write(lo.value);
    178216                else
    179217                        cp0_entry_lo1_write(lo.value);
    180                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    181218                tlbwi();
    182219        }
     
    189226void tlb_modified(istate_t *istate)
    190227{
     228        entry_hi_t hi;
     229        entry_lo_t lo;
    191230        tlb_index_t index;
    192231        uintptr_t badvaddr;
    193         entry_lo_t lo;
    194         entry_hi_t hi;
    195232        pte_t *pte;
    196233
    197         badvaddr = cp0_badvaddr_read();
    198 
    199234        /*
    200235         * Locate the faulting entry in TLB.
    201236         */
    202         hi.value = cp0_entry_hi_read();
    203         tlb_prepare_entry_hi(&hi, hi.asid, badvaddr);
    204         cp0_entry_hi_write(hi.value);
    205237        tlbp();
    206238        index.value = cp0_index_read();
     
    211243        ASSERT(!index.p);
    212244
     245        badvaddr = cp0_badvaddr_read();
     246        hi.value = cp0_entry_hi_read();
     247
     248        /* We may block in find_mapping_and_check(). */
    213249        pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate);
    214250        if (pte) {
     251                if (!tlb_recheck_entry(hi, true))
     252                        return;
     253
    215254                /*
    216255                 * Read the faulting TLB entry.
     
    230269                 * The entry is to be updated in TLB.
    231270                 */
    232                 if ((badvaddr / PAGE_SIZE) % 2 == 0)
     271                if (BANK_SELECT_BIT(badvaddr) == 0)
    233272                        cp0_entry_lo0_write(lo.value);
    234273                else
    235274                        cp0_entry_lo1_write(lo.value);
    236                 cp0_pagemask_write(TLB_PAGE_MASK_16K);
    237275                tlbwi();
    238276        }
     
    296334void tlb_prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr)
    297335{
    298         hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2);
     336        hi->value = 0;
     337        hi->vpn2 = ADDR2VPN2(ALIGN_DOWN(addr, PAGE_SIZE));
    299338        hi->asid = asid;
    300339}
     
    303342void tlb_print(void)
    304343{
    305         page_mask_t mask;
    306         entry_lo_t lo0, lo1;
     344        page_mask_t mask, mask_save;
     345        entry_lo_t lo0, lo0_save, lo1, lo1_save;
    307346        entry_hi_t hi, hi_save;
    308347        unsigned int i;
    309348
    310349        hi_save.value = cp0_entry_hi_read();
    311        
    312         printf("[nr] [asid] [vpn2] [mask] [gvdc] [pfn ]\n");
     350        lo0_save.value = cp0_entry_lo0_read();
     351        lo1_save.value = cp0_entry_lo1_read();
     352        mask_save.value = cp0_pagemask_read();
     353       
     354        printf("[nr] [asid] [vpn2    ] [mask] [gvdc] [pfn     ]\n");
    313355       
    314356        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    321363                lo1.value = cp0_entry_lo1_read();
    322364               
    323                 printf("%-4u %-6u %#6x %#6x  %1u%1u%1u%1u  %#6x\n",
    324                     i, hi.asid, hi.vpn2, mask.mask,
    325                     lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn);
    326                 printf("                           %1u%1u%1u%1u  %#6x\n",
    327                     lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn);
     365                printf("%-4u %-6u %0#10x %-#6x  %1u%1u%1u%1u  %0#10x\n",
     366                    i, hi.asid, VPN22ADDR(hi.vpn2), mask.mask,
     367                    lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn << FRAME_WIDTH);
     368                printf("                               %1u%1u%1u%1u  %0#10x\n",
     369                    lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn << FRAME_WIDTH);
    328370        }
    329371       
    330372        cp0_entry_hi_write(hi_save.value);
     373        cp0_entry_lo0_write(lo0_save.value);
     374        cp0_entry_lo1_write(lo1_save.value);
     375        cp0_pagemask_write(mask_save.value);
    331376}
    332377
     
    334379void tlb_invalidate_all(void)
    335380{
    336         ipl_t ipl;
    337381        entry_lo_t lo0, lo1;
    338382        entry_hi_t hi_save;
    339383        int i;
    340384
     385        ASSERT(interrupts_disabled());
     386
    341387        hi_save.value = cp0_entry_hi_read();
    342         ipl = interrupts_disable();
    343388
    344389        for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) {
     
    358403        }
    359404       
    360         interrupts_restore(ipl);
    361405        cp0_entry_hi_write(hi_save.value);
    362406}
     
    368412void tlb_invalidate_asid(asid_t asid)
    369413{
    370         ipl_t ipl;
    371414        entry_lo_t lo0, lo1;
    372415        entry_hi_t hi, hi_save;
    373416        int i;
    374417
     418        ASSERT(interrupts_disabled());
    375419        ASSERT(asid != ASID_INVALID);
    376420
    377421        hi_save.value = cp0_entry_hi_read();
    378         ipl = interrupts_disable();
    379422       
    380423        for (i = 0; i < TLB_ENTRY_COUNT; i++) {
     
    398441        }
    399442       
    400         interrupts_restore(ipl);
    401443        cp0_entry_hi_write(hi_save.value);
    402444}
     
    412454{
    413455        unsigned int i;
    414         ipl_t ipl;
    415456        entry_lo_t lo0, lo1;
    416457        entry_hi_t hi, hi_save;
    417458        tlb_index_t index;
     459
     460        ASSERT(interrupts_disabled());
    418461       
    419462        if (asid == ASID_INVALID)
     
    421464
    422465        hi_save.value = cp0_entry_hi_read();
    423         ipl = interrupts_disable();
    424466
    425467        for (i = 0; i < cnt + 1; i += 2) {
    426                 hi.value = 0;
    427468                tlb_prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE);
    428469                cp0_entry_hi_write(hi.value);
     
    451492        }
    452493       
    453         interrupts_restore(ipl);
    454494        cp0_entry_hi_write(hi_save.value);
    455495}
Note: See TracChangeset for help on using the changeset viewer.