Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (C) 2006 Martin Decky
  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. /** @addtogroup ppc32mm
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <mm/tlb.h>
  36. #include <arch/mm/tlb.h>
  37. #include <arch/interrupt.h>
  38. #include <mm/as.h>
  39. #include <arch.h>
  40. #include <print.h>
  41. #include <symtab.h>
  42.  
  43.  
  44. /** Try to find PTE for faulting address
  45.  *
  46.  * Try to find PTE for faulting address.
  47.  * The as->lock must be held on entry to this function
  48.  * if lock is true.
  49.  *
  50.  * @param as       Address space.
  51.  * @param lock     Lock/unlock the address space.
  52.  * @param badvaddr Faulting virtual address.
  53.  * @param access   Access mode that caused the fault.
  54.  * @param istate   Pointer to interrupted state.
  55.  * @param pfrc     Pointer to variable where as_page_fault() return code will be stored.
  56.  * @return         PTE on success, NULL otherwise.
  57.  *
  58.  */
  59. static pte_t *find_mapping_and_check(as_t *as, bool lock, __address badvaddr, int access, istate_t *istate, int *pfrc)
  60. {
  61.     /*
  62.      * Check if the mapping exists in page tables.
  63.      */
  64.     pte_t *pte = page_mapping_find(as, badvaddr);
  65.     if ((pte) && (pte->p)) {
  66.         /*
  67.          * Mapping found in page tables.
  68.          * Immediately succeed.
  69.          */
  70.         return pte;
  71.     } else {
  72.         int rc;
  73.    
  74.         /*
  75.          * Mapping not found in page tables.
  76.          * Resort to higher-level page fault handler.
  77.          */
  78.         page_table_unlock(as, lock);
  79.         switch (rc = as_page_fault(badvaddr, access, istate)) {
  80.             case AS_PF_OK:
  81.                 /*
  82.                  * The higher-level page fault handler succeeded,
  83.                  * The mapping ought to be in place.
  84.                  */
  85.                 page_table_lock(as, lock);
  86.                 pte = page_mapping_find(as, badvaddr);
  87.                 ASSERT((pte) && (pte->p));
  88.                 return pte;
  89.             case AS_PF_DEFER:
  90.                 page_table_lock(as, lock);
  91.                 *pfrc = rc;
  92.                 return NULL;
  93.             case AS_PF_FAULT:
  94.                 page_table_lock(as, lock);
  95.                 printf("Page fault.\n");
  96.                 *pfrc = rc;
  97.                 return NULL;
  98.             default:
  99.                 panic("unexpected rc (%d)\n", rc);
  100.         }  
  101.     }
  102. }
  103.  
  104.  
  105. static void pht_refill_fail(__address badvaddr, istate_t *istate)
  106. {
  107.     char *symbol = "";
  108.     char *sym2 = "";
  109.  
  110.     char *s = get_symtab_entry(istate->pc);
  111.     if (s)
  112.         symbol = s;
  113.     s = get_symtab_entry(istate->lr);
  114.     if (s)
  115.         sym2 = s;
  116.     panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
  117. }
  118.  
  119.  
  120. static void pht_insert(const __address vaddr, const pfn_t pfn)
  121. {
  122.     __u32 page = (vaddr >> 12) & 0xffff;
  123.     __u32 api = (vaddr >> 22) & 0x3f;
  124.    
  125.     __u32 vsid;
  126.     asm volatile (
  127.         "mfsrin %0, %1\n"
  128.         : "=r" (vsid)
  129.         : "r" (vaddr)
  130.     );
  131.    
  132.     __u32 sdr1;
  133.     asm volatile (
  134.         "mfsdr1 %0\n"
  135.         : "=r" (sdr1)
  136.     );
  137.     phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
  138.    
  139.     /* Primary hash (xor) */
  140.     __u32 h = 0;
  141.     __u32 hash = vsid ^ page;
  142.     __u32 base = (hash & 0x3ff) << 3;
  143.     __u32 i;
  144.     bool found = false;
  145.    
  146.     /* Find unused or colliding
  147.        PTE in PTEG */
  148.     for (i = 0; i < 8; i++) {
  149.         if ((!phte[base + i].v) || ((phte[base + i].vsid == vsid) && (phte[base + i].api == api))) {
  150.             found = true;
  151.             break;
  152.         }
  153.     }
  154.    
  155.     if (!found) {
  156.         /* Secondary hash (not) */
  157.         __u32 base2 = (~hash & 0x3ff) << 3;
  158.        
  159.         /* Find unused or colliding
  160.            PTE in PTEG */
  161.         for (i = 0; i < 8; i++) {
  162.             if ((!phte[base2 + i].v) || ((phte[base2 + i].vsid == vsid) && (phte[base2 + i].api == api))) {
  163.                 found = true;
  164.                 base = base2;
  165.                 h = 1;
  166.                 break;
  167.             }
  168.         }
  169.        
  170.         if (!found) {
  171.             // TODO: A/C precedence groups
  172.             i = page % 8;
  173.         }
  174.     }
  175.    
  176.     phte[base + i].v = 1;
  177.     phte[base + i].vsid = vsid;
  178.     phte[base + i].h = h;
  179.     phte[base + i].api = api;
  180.     phte[base + i].rpn = pfn;
  181.     phte[base + i].r = 0;
  182.     phte[base + i].c = 0;
  183.     phte[base + i].pp = 2; // FIXME
  184. }
  185.  
  186.  
  187. static void pht_real_insert(const __address vaddr, const pfn_t pfn)
  188. {
  189.     __u32 page = (vaddr >> 12) & 0xffff;
  190.     __u32 api = (vaddr >> 22) & 0x3f;
  191.    
  192.     __u32 vsid;
  193.     asm volatile (
  194.         "mfsrin %0, %1\n"
  195.         : "=r" (vsid)
  196.         : "r" (vaddr)
  197.     );
  198.    
  199.     __u32 sdr1;
  200.     asm volatile (
  201.         "mfsdr1 %0\n"
  202.         : "=r" (sdr1)
  203.     );
  204.     phte_t *phte_physical = (phte_t *) (sdr1 & 0xffff0000);
  205.    
  206.     /* Primary hash (xor) */
  207.     __u32 h = 0;
  208.     __u32 hash = vsid ^ page;
  209.     __u32 base = (hash & 0x3ff) << 3;
  210.     __u32 i;
  211.     bool found = false;
  212.    
  213.     /* Find unused or colliding
  214.        PTE in PTEG */
  215.     for (i = 0; i < 8; i++) {
  216.         if ((!phte_physical[base + i].v) || ((phte_physical[base + i].vsid == vsid) && (phte_physical[base + i].api == api))) {
  217.             found = true;
  218.             break;
  219.         }
  220.     }
  221.    
  222.     if (!found) {
  223.         /* Secondary hash (not) */
  224.         __u32 base2 = (~hash & 0x3ff) << 3;
  225.        
  226.         /* Find unused or colliding
  227.            PTE in PTEG */
  228.         for (i = 0; i < 8; i++) {
  229.             if ((!phte_physical[base2 + i].v) || ((phte_physical[base2 + i].vsid == vsid) && (phte_physical[base2 + i].api == api))) {
  230.                 found = true;
  231.                 base = base2;
  232.                 h = 1;
  233.                 break;
  234.             }
  235.         }
  236.        
  237.         if (!found) {
  238.             // TODO: A/C precedence groups
  239.             i = page % 8;
  240.         }
  241.     }
  242.    
  243.     phte_physical[base + i].v = 1;
  244.     phte_physical[base + i].vsid = vsid;
  245.     phte_physical[base + i].h = h;
  246.     phte_physical[base + i].api = api;
  247.     phte_physical[base + i].rpn = pfn;
  248.     phte_physical[base + i].r = 0;
  249.     phte_physical[base + i].c = 0;
  250.     phte_physical[base + i].pp = 2; // FIXME
  251. }
  252.  
  253.  
  254. /** Process Instruction/Data Storage Interrupt
  255.  *
  256.  * @param n Interrupt vector number.
  257.  * @param istate Interrupted register context.
  258.  *
  259.  */
  260. void pht_refill(int n, istate_t *istate)
  261. {
  262.     __address badvaddr;
  263.     pte_t *pte;
  264.     int pfrc;
  265.     as_t *as;
  266.     bool lock;
  267.    
  268.     if (AS == NULL) {
  269.         as = AS_KERNEL;
  270.         lock = false;
  271.     } else {
  272.         as = AS;
  273.         lock = true;
  274.     }
  275.    
  276.     if (n == VECTOR_DATA_STORAGE) {
  277.         asm volatile (
  278.             "mfdar %0\n"
  279.             : "=r" (badvaddr)
  280.         );
  281.     } else
  282.         badvaddr = istate->pc;
  283.        
  284.     page_table_lock(as, lock);
  285.    
  286.     pte = find_mapping_and_check(as, lock, badvaddr, PF_ACCESS_READ /* FIXME */, istate, &pfrc);
  287.     if (!pte) {
  288.         switch (pfrc) {
  289.             case AS_PF_FAULT:
  290.                 goto fail;
  291.                 break;
  292.             case AS_PF_DEFER:
  293.                 /*
  294.                  * The page fault came during copy_from_uspace()
  295.                  * or copy_to_uspace().
  296.                  */
  297.                 page_table_unlock(as, lock);
  298.                 return;
  299.             default:
  300.                 panic("Unexpected pfrc (%d)\n", pfrc);
  301.         }
  302.     }
  303.    
  304.     pte->a = 1; /* Record access to PTE */
  305.     pht_insert(badvaddr, pte->pfn);
  306.    
  307.     page_table_unlock(as, lock);
  308.     return;
  309.    
  310. fail:
  311.     page_table_unlock(as, lock);
  312.     pht_refill_fail(badvaddr, istate);
  313. }
  314.  
  315.  
  316. /** Process Instruction/Data Storage Interrupt in Real Mode
  317.  *
  318.  * @param n Interrupt vector number.
  319.  * @param istate Interrupted register context.
  320.  *
  321.  */
  322. bool pht_real_refill(int n, istate_t *istate)
  323. {
  324.     __address badvaddr;
  325.    
  326.     if (n == VECTOR_DATA_STORAGE) {
  327.         asm volatile (
  328.             "mfdar %0\n"
  329.             : "=r" (badvaddr)
  330.         );
  331.     } else
  332.         badvaddr = istate->pc;
  333.    
  334.     __u32 physmem;
  335.     asm volatile (
  336.         "mfsprg3 %0\n"
  337.         : "=r" (physmem)
  338.     );
  339.    
  340.     if ((badvaddr >= PA2KA(0)) && (badvaddr < PA2KA(physmem))) {
  341.         pht_real_insert(badvaddr, KA2PA(badvaddr) >> 12);
  342.         return true;
  343.     }
  344.    
  345.     return false;
  346. }
  347.  
  348.  
  349. void tlb_arch_init(void)
  350. {
  351.     tlb_invalidate_all();
  352. }
  353.  
  354.  
  355. void tlb_invalidate_all(void)
  356. {
  357.     asm volatile (
  358.         "tlbia\n"
  359.         "tlbsync\n"
  360.     );
  361. }
  362.  
  363.  
  364. void tlb_invalidate_asid(asid_t asid)
  365. {
  366.     // TODO
  367.     tlb_invalidate_all();
  368. }
  369.  
  370.  
  371. void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
  372. {
  373.     // TODO
  374.     tlb_invalidate_all();
  375. }
  376.  
  377.  
  378. void tlb_print(void)
  379. {
  380.     __u32 sr;
  381.    
  382.     for (sr = 0; sr < 16; sr++) {
  383.         __u32 vsid;
  384.         asm volatile (
  385.             "mfsrin %0, %1\n"
  386.             : "=r" (vsid)
  387.             : "r" (sr << 28)
  388.         );
  389.         printf("vsid[%#x]=%#x\n", sr << 28, vsid);
  390.     }
  391. }
  392.  
  393. /** @}
  394.  */
  395.