Subversion Repositories HelenOS

Rev

Rev 395 | Rev 397 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2003-2004 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. #include <arch/mm/tlb.h>
  30. #include <arch/mm/asid.h>
  31. #include <mm/tlb.h>
  32. #include <mm/page.h>
  33. #include <mm/vm.h>
  34. #include <arch/cp0.h>
  35. #include <panic.h>
  36. #include <arch.h>
  37. #include <symtab.h>
  38. #include <synch/spinlock.h>
  39. #include <print.h>
  40. #include <debug.h>
  41.  
  42. static void tlb_refill_fail(struct exception_regdump *pstate);
  43. static void tlb_invalid_fail(struct exception_regdump *pstate);
  44. static void tlb_modified_fail(struct exception_regdump *pstate);
  45.  
  46. static pte_t *find_mapping_and_check(__address badvaddr);
  47. static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn);
  48.  
  49. /** Initialize TLB
  50.  *
  51.  * Initialize TLB.
  52.  * Invalidate all entries and mark wired entries.
  53.  */
  54. void tlb_init_arch(void)
  55. {
  56.     int i;
  57.  
  58.     cp0_pagemask_write(TLB_PAGE_MASK_16K);
  59.     cp0_entry_hi_write(0);
  60.     cp0_entry_lo0_write(0);
  61.     cp0_entry_lo1_write(0);
  62.  
  63.     /*
  64.      * Invalidate all entries.
  65.      */
  66.     for (i = 0; i < TLB_SIZE; i++) {
  67.         cp0_index_write(i);
  68.         tlbwi();
  69.     }
  70.    
  71.     /*
  72.      * The kernel is going to make use of some wired
  73.      * entries (e.g. mapping kernel stacks in kseg3).
  74.      */
  75.     cp0_wired_write(TLB_WIRED);
  76. }
  77.  
  78. /** Process TLB Refill Exception
  79.  *
  80.  * Process TLB Refill Exception.
  81.  *
  82.  * @param pstate Interrupted register context.
  83.  */
  84. void tlb_refill(struct exception_regdump *pstate)
  85. {
  86.     entry_lo_t lo;
  87.     __address badvaddr;
  88.     pte_t *pte;
  89.    
  90.     badvaddr = cp0_badvaddr_read();
  91.    
  92.     spinlock_lock(&VM->lock);      
  93.     pte = find_mapping_and_check(badvaddr);
  94.     if (!pte)
  95.         goto fail;
  96.  
  97.     /*
  98.      * Record access to PTE.
  99.      */
  100.     pte->a = 1;
  101.  
  102.     prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
  103.  
  104.     /*
  105.      * New entry is to be inserted into TLB
  106.      */
  107.     if ((badvaddr/PAGE_SIZE) % 2 == 0) {
  108.         cp0_entry_lo0_write(lo.value);
  109.         cp0_entry_lo1_write(0);
  110.     }
  111.     else {
  112.         cp0_entry_lo0_write(0);
  113.         cp0_entry_lo1_write(lo.value);
  114.     }
  115.     tlbwr();
  116.  
  117.     spinlock_unlock(&VM->lock);
  118.     return;
  119.    
  120. fail:
  121.     spinlock_unlock(&VM->lock);
  122.     tlb_refill_fail(pstate);
  123. }
  124.  
  125. /** Process TLB Invalid Exception
  126.  *
  127.  * Process TLB Invalid Exception.
  128.  *
  129.  * @param pstate Interrupted register context.
  130.  */
  131. void tlb_invalid(struct exception_regdump *pstate)
  132. {
  133.     tlb_index_t index;
  134.     __address badvaddr;
  135.     entry_lo_t lo;
  136.     pte_t *pte;
  137.  
  138.     badvaddr = cp0_badvaddr_read();
  139.  
  140.     /*
  141.      * Locate the faulting entry in TLB.
  142.      */
  143.     tlbp();
  144.     index.value = cp0_index_read();
  145.    
  146.     spinlock_lock(&VM->lock);  
  147.    
  148.     /*
  149.      * Fail if the entry is not in TLB.
  150.      */
  151.     if (index.p) {
  152.         printf("TLB entry not found.\n");
  153.         goto fail;
  154.     }
  155.  
  156.     pte = find_mapping_and_check(badvaddr);
  157.     if (!pte)
  158.         goto fail;
  159.  
  160.     /*
  161.      * Read the faulting TLB entry.
  162.      */
  163.     tlbr();
  164.  
  165.     /*
  166.      * Record access to PTE.
  167.      */
  168.     pte->a = 1;
  169.  
  170.     prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
  171.  
  172.     /*
  173.      * The entry is to be updated in TLB.
  174.      */
  175.     if ((badvaddr/PAGE_SIZE) % 2 == 0)
  176.         cp0_entry_lo0_write(lo.value);
  177.     else
  178.         cp0_entry_lo1_write(lo.value);
  179.     tlbwi();
  180.  
  181.     spinlock_unlock(&VM->lock);
  182.     return;
  183.    
  184. fail:
  185.     spinlock_unlock(&VM->lock);
  186.     tlb_invalid_fail(pstate);
  187. }
  188.  
  189. /** Process TLB Modified Exception
  190.  *
  191.  * Process TLB Modified Exception.
  192.  *
  193.  * @param pstate Interrupted register context.
  194.  */
  195. void tlb_modified(struct exception_regdump *pstate)
  196. {
  197.     tlb_index_t index;
  198.     __address badvaddr;
  199.     entry_lo_t lo;
  200.     pte_t *pte;
  201.  
  202.     badvaddr = cp0_badvaddr_read();
  203.  
  204.     /*
  205.      * Locate the faulting entry in TLB.
  206.      */
  207.     tlbp();
  208.     index.value = cp0_index_read();
  209.    
  210.     spinlock_lock(&VM->lock);  
  211.    
  212.     /*
  213.      * Fail if the entry is not in TLB.
  214.      */
  215.     if (index.p) {
  216.         printf("TLB entry not found.\n");
  217.         goto fail;
  218.     }
  219.  
  220.     pte = find_mapping_and_check(badvaddr);
  221.     if (!pte)
  222.         goto fail;
  223.  
  224.     /*
  225.      * Fail if the page is not writable.
  226.      */
  227.     if (!pte->w)
  228.         goto fail;
  229.  
  230.     /*
  231.      * Read the faulting TLB entry.
  232.      */
  233.     tlbr();
  234.  
  235.     /*
  236.      * Record access and write to PTE.
  237.      */
  238.     pte->a = 1;
  239.     pte->d = 1;
  240.  
  241.     prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
  242.  
  243.     /*
  244.      * The entry is to be updated in TLB.
  245.      */
  246.     if ((badvaddr/PAGE_SIZE) % 2 == 0)
  247.         cp0_entry_lo0_write(lo.value);
  248.     else
  249.         cp0_entry_lo1_write(lo.value);
  250.     tlbwi();
  251.  
  252.     spinlock_unlock(&VM->lock);
  253.     return;
  254.    
  255. fail:
  256.     spinlock_unlock(&VM->lock);
  257.     tlb_modified_fail(pstate);
  258. }
  259.  
  260. void tlb_refill_fail(struct exception_regdump *pstate)
  261. {
  262.     char *symbol = "";
  263.     char *sym2 = "";
  264.  
  265.     char *s = get_symtab_entry(pstate->epc);
  266.     if (s)
  267.         symbol = s;
  268.     s = get_symtab_entry(pstate->ra);
  269.     if (s)
  270.         sym2 = s;
  271.     panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
  272. }
  273.  
  274.  
  275. void tlb_invalid_fail(struct exception_regdump *pstate)
  276. {
  277.     char *symbol = "";
  278.  
  279.     char *s = get_symtab_entry(pstate->epc);
  280.     if (s)
  281.         symbol = s;
  282.     panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
  283. }
  284.  
  285. void tlb_modified_fail(struct exception_regdump *pstate)
  286. {
  287.     char *symbol = "";
  288.  
  289.     char *s = get_symtab_entry(pstate->epc);
  290.     if (s)
  291.         symbol = s;
  292.     panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
  293. }
  294.  
  295. /** Invalidate TLB entries with specified ASID
  296.  *
  297.  * Invalidate TLB entries with specified ASID.
  298.  *
  299.  * @param asid ASID.
  300.  */
  301. void tlb_invalidate(asid_t asid)
  302. {
  303.     entry_hi_t hi;
  304.     pri_t pri;
  305.     int i; 
  306.    
  307.     ASSERT(asid != ASID_INVALID);
  308.  
  309.     pri = cpu_priority_high();
  310.    
  311.     for (i = 0; i < TLB_SIZE; i++) {
  312.         cp0_index_write(i);
  313.         tlbr();
  314.        
  315.         hi.value = cp0_entry_hi_read();
  316.         if (hi.asid == asid) {
  317.             cp0_pagemask_write(TLB_PAGE_MASK_16K);
  318.             cp0_entry_hi_write(0);
  319.             cp0_entry_lo0_write(0);
  320.             cp0_entry_lo1_write(0);
  321.             tlbwi();
  322.         }
  323.     }
  324.    
  325.     cpu_priority_restore(pri);
  326. }
  327.  
  328. /** Try to find PTE for faulting address
  329.  *
  330.  * Try to find PTE for faulting address.
  331.  * The VM->lock must be held on entry to this function.
  332.  *
  333.  * @param badvaddr Faulting virtual address.
  334.  *
  335.  * @return PTE on success, NULL otherwise.
  336.  */
  337. pte_t *find_mapping_and_check(__address badvaddr)
  338. {
  339.     entry_hi_t hi;
  340.     pte_t *pte;
  341.  
  342.     hi.value = cp0_entry_hi_read();
  343.  
  344.     /*
  345.      * Handler cannot succeed if the ASIDs don't match.
  346.      */
  347.     if (hi.asid != VM->asid) {
  348.         printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
  349.         return NULL;
  350.     }
  351.    
  352.     /*
  353.      * Handler cannot succeed if badvaddr has no mapping.
  354.      */
  355.     pte = find_mapping(badvaddr, 0);
  356.     if (!pte) {
  357.         printf("No such mapping.\n");
  358.         return NULL;
  359.     }
  360.  
  361.     /*
  362.      * Handler cannot succeed if the mapping is marked as invalid.
  363.      */
  364.     if (!pte->v) {
  365.         printf("Invalid mapping.\n");
  366.         return NULL;
  367.     }
  368.  
  369.     return pte;
  370. }
  371.  
  372. void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
  373. {
  374.     lo->g = g;
  375.     lo->v = v;
  376.     lo->d = d;
  377.     lo->c = c;
  378.     lo->pfn = pfn;
  379.     lo->zero = 0;
  380. }
  381.