Subversion Repositories HelenOS-historic

Rev

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

  1. /*
  2.  * Copyright (C) 2006 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. /*
  30.  * TLB management.
  31.  */
  32.  
  33. #include <mm/tlb.h>
  34. #include <mm/asid.h>
  35. #include <mm/page.h>
  36. #include <mm/as.h>
  37. #include <arch/mm/tlb.h>
  38. #include <arch/mm/page.h>
  39. #include <arch/barrier.h>
  40. #include <arch/interrupt.h>
  41. #include <typedefs.h>
  42. #include <panic.h>
  43. #include <arch.h>
  44.  
  45. /** Invalidate all TLB entries. */
  46. void tlb_invalidate_all(void)
  47. {
  48.     /* TODO */
  49. }
  50.  
  51. /** Invalidate entries belonging to an address space.
  52.  *
  53.  * @param asid Address space identifier.
  54.  */
  55. void tlb_invalidate_asid(asid_t asid)
  56. {
  57.     /* TODO */
  58. }
  59.  
  60. /** Insert data into data translation cache.
  61.  *
  62.  * @param va Virtual page address.
  63.  * @param asid Address space identifier.
  64.  * @param entry The rest of TLB entry as required by TLB insertion format.
  65.  */
  66. void dtc_mapping_insert(__address va, asid_t asid, tlb_entry_t entry)
  67. {
  68.     tc_mapping_insert(va, asid, entry, true);
  69. }
  70.  
  71. /** Insert data into instruction translation cache.
  72.  *
  73.  * @param va Virtual page address.
  74.  * @param asid Address space identifier.
  75.  * @param entry The rest of TLB entry as required by TLB insertion format.
  76.  */
  77. void itc_mapping_insert(__address va, asid_t asid, tlb_entry_t entry)
  78. {
  79.     tc_mapping_insert(va, asid, entry, false);
  80. }
  81.  
  82. /** Insert data into instruction or data translation cache.
  83.  *
  84.  * @param va Virtual page address.
  85.  * @param asid Address space identifier.
  86.  * @param entry The rest of TLB entry as required by TLB insertion format.
  87.  * @param dtc If true, insert into data translation cache, use instruction translation cache otherwise.
  88.  */
  89. void tc_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtc)
  90. {
  91.     region_register rr;
  92.     bool restore_rr = false;
  93.  
  94.     rr.word = rr_read(VA2VRN(va));
  95.     if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) {
  96.         /*
  97.          * The selected region register does not contain required RID.
  98.          * Save the old content of the register and replace the RID.
  99.          */
  100.         region_register rr0;
  101.  
  102.         rr0 = rr;
  103.         rr0.map.rid = ASID2RID(asid, VA2VRN(va));
  104.         rr_write(VA2VRN(va), rr0.word);
  105.         srlz_d();
  106.         srlz_i();
  107.     }
  108.    
  109.     __asm__ volatile (
  110.         "mov r8=psr;;\n"
  111.         "rsm %0;;\n"            /* PSR_IC_MASK */
  112.         "srlz.d;;\n"
  113.         "srlz.i;;\n"
  114.         "mov cr.ifa=%1\n"       /* va */
  115.         "mov cr.itir=%2;;\n"        /* entry.word[1] */
  116.         "cmp.eq p6,p7 = %4,r0;;\n"  /* decide between itc and dtc */
  117.         "(p6) itc.i %3;;\n"
  118.         "(p7) itc.d %3;;\n"
  119.         "mov psr.l=r8;;\n"
  120.         "srlz.d;;\n"
  121.         :
  122.         : "i" (PSR_IC_MASK), "r" (va), "r" (entry.word[1]), "r" (entry.word[0]), "r" (dtc)
  123.         : "p6", "p7", "r8"
  124.     );
  125.    
  126.     if (restore_rr) {
  127.         rr_write(VA2VRN(va), rr.word);
  128.         srlz_d();
  129.         srlz_i();
  130.     }
  131. }
  132.  
  133. /** Insert data into instruction translation register.
  134.  *
  135.  * @param va Virtual page address.
  136.  * @param asid Address space identifier.
  137.  * @param entry The rest of TLB entry as required by TLB insertion format.
  138.  * @param tr Translation register.
  139.  */
  140. void itr_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, index_t tr)
  141. {
  142.     tr_mapping_insert(va, asid, entry, false, tr);
  143. }
  144.  
  145. /** Insert data into data translation register.
  146.  *
  147.  * @param va Virtual page address.
  148.  * @param asid Address space identifier.
  149.  * @param entry The rest of TLB entry as required by TLB insertion format.
  150.  * @param tr Translation register.
  151.  */
  152. void dtr_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, index_t tr)
  153. {
  154.     tr_mapping_insert(va, asid, entry, true, tr);
  155. }
  156.  
  157. /** Insert data into instruction or data translation register.
  158.  *
  159.  * @param va Virtual page address.
  160.  * @param asid Address space identifier.
  161.  * @param entry The rest of TLB entry as required by TLB insertion format.
  162.  * @param dtc If true, insert into data translation register, use instruction translation register otherwise.
  163.  * @param tr Translation register.
  164.  */
  165. void tr_mapping_insert(__address va, asid_t asid, tlb_entry_t entry, bool dtr, index_t tr)
  166. {
  167.     region_register rr;
  168.     bool restore_rr = false;
  169.  
  170.     rr.word = rr_read(VA2VRN(va));
  171.     if ((restore_rr = (rr.map.rid != ASID2RID(asid, VA2VRN(va))))) {
  172.         /*
  173.          * The selected region register does not contain required RID.
  174.          * Save the old content of the register and replace the RID.
  175.          */
  176.         region_register rr0;
  177.  
  178.         rr0 = rr;
  179.         rr0.map.rid = ASID2RID(asid, VA2VRN(va));
  180.         rr_write(VA2VRN(va), rr0.word);
  181.         srlz_d();
  182.         srlz_i();
  183.     }
  184.  
  185.     __asm__ volatile (
  186.         "mov r8=psr;;\n"
  187.         "rsm %0;;\n"            /* PSR_IC_MASK */
  188.         "srlz.d;;\n"
  189.         "srlz.i;;\n"
  190.         "mov cr.ifa=%1\n"           /* va */         
  191.         "mov cr.itir=%2;;\n"        /* entry.word[1] */
  192.         "cmp.eq p6,p7=%5,r0;;\n"    /* decide between itr and dtr */
  193.         "(p6) itr.i itr[%4]=%3;;\n"
  194.         "(p7) itr.d dtr[%4]=%3;;\n"
  195.         "mov psr.l=r8;;\n"
  196.         "srlz.d;;\n"
  197.         :
  198.         : "i" (PSR_IC_MASK), "r" (va), "r" (entry.word[1]), "r" (entry.word[0]), "r" (tr), "r" (dtr)
  199.         : "p6", "p7", "r8"
  200.     );
  201.    
  202.     if (restore_rr) {
  203.         rr_write(VA2VRN(va), rr.word);
  204.         srlz_d();
  205.         srlz_i();
  206.     }
  207. }
  208.  
  209. /** Insert data into DTLB.
  210.  *
  211.  * @param va Virtual page address.
  212.  * @param asid Address space identifier.
  213.  * @param entry The rest of TLB entry as required by TLB insertion format.
  214.  * @param dtr If true, insert into data translation register, use data translation cache otherwise.
  215.  * @param tr Translation register if dtr is true, ignored otherwise.
  216.  */
  217. void dtlb_kernel_mapping_insert(__address page, __address frame, bool dtr, index_t tr)
  218. {
  219.     tlb_entry_t entry;
  220.    
  221.     entry.word[0] = 0;
  222.     entry.word[1] = 0;
  223.    
  224.     entry.p = true;         /* present */
  225.     entry.ma = MA_WRITEBACK;
  226.     entry.a = true;         /* already accessed */
  227.     entry.d = true;         /* already dirty */
  228.     entry.pl = PL_KERNEL;
  229.     entry.ar = AR_READ | AR_WRITE;
  230.     entry.ppn = frame >> PPN_SHIFT;
  231.     entry.ps = PAGE_WIDTH;
  232.    
  233.     if (dtr)
  234.         dtr_mapping_insert(page, ASID_KERNEL, entry, tr);
  235.     else
  236.         dtc_mapping_insert(page, ASID_KERNEL, entry);
  237. }
  238.  
  239. /** Copy content of PTE into data translation cache.
  240.  *
  241.  * @param t PTE.
  242.  */
  243. void dtc_pte_copy(pte_t *t)
  244. {
  245.     tlb_entry_t entry;
  246.  
  247.     entry.word[0] = 0;
  248.     entry.word[1] = 0;
  249.    
  250.     entry.p = t->p;
  251.     entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE;
  252.     entry.a = t->a;
  253.     entry.d = t->d;
  254.     entry.pl = t->k ? PL_KERNEL : PL_USER;
  255.     entry.ar = t->w ? AR_WRITE : AR_READ;
  256.     entry.ppn = t->frame >> PPN_SHIFT;
  257.     entry.ps = PAGE_WIDTH;
  258.    
  259.     dtc_mapping_insert(t->page, t->as->asid, entry);
  260. }
  261.  
  262. /** Copy content of PTE into instruction translation cache.
  263.  *
  264.  * @param t PTE.
  265.  */
  266. void itc_pte_copy(pte_t *t)
  267. {
  268.     tlb_entry_t entry;
  269.  
  270.     entry.word[0] = 0;
  271.     entry.word[1] = 0;
  272.    
  273.     ASSERT(t->x);
  274.    
  275.     entry.p = t->p;
  276.     entry.ma = t->c ? MA_WRITEBACK : MA_UNCACHEABLE;
  277.     entry.a = t->a;
  278.     entry.pl = t->k ? PL_KERNEL : PL_USER;
  279.     entry.ar = t->x ? (AR_EXECUTE | AR_READ) : AR_READ;
  280.     entry.ppn = t->frame >> PPN_SHIFT;
  281.     entry.ps = PAGE_WIDTH;
  282.    
  283.     itc_mapping_insert(t->page, t->as->asid, entry);
  284. }
  285.  
  286. /** Instruction TLB fault handler for faults with VHPT turned off.
  287.  *
  288.  * @param vector Interruption vector.
  289.  * @param pstate Structure with saved interruption state.
  290.  */
  291. void alternate_instruction_tlb_fault(__u64 vector, struct exception_regdump *pstate)
  292. {
  293.     region_register rr;
  294.     __address va;
  295.     pte_t *t;
  296.    
  297.     va = pstate->cr_ifa;    /* faulting address */
  298.     t = page_mapping_find(AS, va);
  299.     if (t) {
  300.         /*
  301.          * The mapping was found in software page hash table.
  302.          * Insert it into data translation cache.
  303.          */
  304.         itc_pte_copy(t);
  305.     } else {
  306.         /*
  307.          * Forward the page fault to address space page fault handler.
  308.          */
  309.         if (!as_page_fault(va)) {
  310.             panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid);
  311.         }
  312.     }
  313. }
  314.  
  315. /** Data TLB fault handler for faults with VHPT turned off.
  316.  *
  317.  * @param vector Interruption vector.
  318.  * @param pstate Structure with saved interruption state.
  319.  */
  320. void alternate_data_tlb_fault(__u64 vector, struct exception_regdump *pstate)
  321. {
  322.     region_register rr;
  323.     rid_t rid;
  324.     __address va;
  325.     pte_t *t;
  326.    
  327.     va = pstate->cr_ifa;    /* faulting address */
  328.     rr.word = rr_read(VA2VRN(va));
  329.     rid = rr.map.rid;
  330.     if (RID2ASID(rid) == ASID_KERNEL) {
  331.         if (VA2VRN(va) == VRN_KERNEL) {
  332.             /*
  333.              * Provide KA2PA(identity) mapping for faulting piece of
  334.              * kernel address space.
  335.              */
  336.             dtlb_kernel_mapping_insert(va, KA2PA(va), false, 0);
  337.             return;
  338.         }
  339.     }
  340.  
  341.     t = page_mapping_find(AS, va);
  342.     if (t) {
  343.         /*
  344.          * The mapping was found in software page hash table.
  345.          * Insert it into data translation cache.
  346.          */
  347.         dtc_pte_copy(t);
  348.     } else {
  349.         /*
  350.          * Forward the page fault to address space page fault handler.
  351.          */
  352.         if (!as_page_fault(va)) {
  353.             panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid);
  354.         }
  355.     }
  356. }
  357.  
  358. /** Data nested TLB fault handler.
  359.  *
  360.  * This fault should not occur.
  361.  *
  362.  * @param vector Interruption vector.
  363.  * @param pstate Structure with saved interruption state.
  364.  */
  365. void data_nested_tlb_fault(__u64 vector, struct exception_regdump *pstate)
  366. {
  367.     panic("%s\n", __FUNCTION__);
  368. }
  369.  
  370. /** Data Dirty bit fault handler.
  371.  *
  372.  * @param vector Interruption vector.
  373.  * @param pstate Structure with saved interruption state.
  374.  */
  375. void data_dirty_bit_fault(__u64 vector, struct exception_regdump *pstate)
  376. {
  377.     pte_t *t;
  378.  
  379.     t = page_mapping_find(AS, pstate->cr_ifa);
  380.     ASSERT(t && t->p);
  381.     if (t && t->p) {
  382.         /*
  383.          * Update the Dirty bit in page tables and reinsert
  384.          * the mapping into DTC.
  385.          */
  386.         t->d = true;
  387.         dtc_pte_copy(t);
  388.     }
  389. }
  390.  
  391. /** Instruction access bit fault handler.
  392.  *
  393.  * @param vector Interruption vector.
  394.  * @param pstate Structure with saved interruption state.
  395.  */
  396. void instruction_access_bit_fault(__u64 vector, struct exception_regdump *pstate)
  397. {
  398.     pte_t *t;
  399.  
  400.     t = page_mapping_find(AS, pstate->cr_ifa);
  401.     ASSERT(t && t->p);
  402.     if (t && t->p) {
  403.         /*
  404.          * Update the Accessed bit in page tables and reinsert
  405.          * the mapping into ITC.
  406.          */
  407.         t->a = true;
  408.         itc_pte_copy(t);
  409.     }
  410. }
  411.  
  412. /** Data access bit fault handler.
  413.  *
  414.  * @param vector Interruption vector.
  415.  * @param pstate Structure with saved interruption state.
  416.  */
  417. void data_access_bit_fault(__u64 vector, struct exception_regdump *pstate)
  418. {
  419.     pte_t *t;
  420.  
  421.     t = page_mapping_find(AS, pstate->cr_ifa);
  422.     ASSERT(t && t->p);
  423.     if (t && t->p) {
  424.         /*
  425.          * Update the Accessed bit in page tables and reinsert
  426.          * the mapping into DTC.
  427.          */
  428.         t->a = true;
  429.         dtc_pte_copy(t);
  430.     }
  431. }
  432.  
  433. /** Page not present fault handler.
  434.  *
  435.  * @param vector Interruption vector.
  436.  * @param pstate Structure with saved interruption state.
  437.  */
  438. void page_not_present(__u64 vector, struct exception_regdump *pstate)
  439. {
  440.     region_register rr;
  441.     __address va;
  442.     pte_t *t;
  443.    
  444.     va = pstate->cr_ifa;    /* faulting address */
  445.     t = page_mapping_find(AS, va);
  446.     ASSERT(t);
  447.    
  448.     if (t->p) {
  449.         /*
  450.          * If the Present bit is set in page hash table, just copy it
  451.          * and update ITC/DTC.
  452.          */
  453.         if (t->x)
  454.             itc_pte_copy(t);
  455.         else
  456.             dtc_pte_copy(t);
  457.     } else {
  458.         if (!as_page_fault(va)) {
  459.             panic("%s: va=%P, rid=%d\n", __FUNCTION__, pstate->cr_ifa, rr.map.rid);
  460.         }
  461.     }
  462. }
  463.