Subversion Repositories HelenOS

Rev

Rev 2787 | 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. /** @addtogroup genarchmm
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file
  35.  * @brief   Virtual Address Translation for hierarchical 4-level page tables.
  36.  */
  37.  
  38. #include <genarch/mm/page_pt.h>
  39. #include <mm/page.h>
  40. #include <mm/frame.h>
  41. #include <mm/as.h>
  42. #include <arch/mm/page.h>
  43. #include <arch/mm/as.h>
  44. #include <arch/types.h>
  45. #include <arch/asm.h>
  46. #include <memstr.h>
  47.  
  48. static void pt_mapping_insert(as_t *as, uintptr_t page, uintptr_t frame, int flags);
  49. static void pt_mapping_remove(as_t *as, uintptr_t page);
  50. static pte_t *pt_mapping_find(as_t *as, uintptr_t page);
  51.  
  52. page_mapping_operations_t pt_mapping_operations = {
  53.     .mapping_insert = pt_mapping_insert,
  54.     .mapping_remove = pt_mapping_remove,
  55.     .mapping_find = pt_mapping_find
  56. };
  57.  
  58. /** Map page to frame using hierarchical page tables.
  59.  *
  60.  * Map virtual address page to physical address frame
  61.  * using flags.
  62.  *
  63.  * The page table must be locked and interrupts must be disabled.
  64.  *
  65.  * @param as Address space to wich page belongs.
  66.  * @param page Virtual address of the page to be mapped.
  67.  * @param frame Physical address of memory frame to which the mapping is done.
  68.  * @param flags Flags to be used for mapping.
  69.  */
  70. void pt_mapping_insert(as_t *as, uintptr_t page, uintptr_t frame, int flags)
  71. {
  72.     pte_t *ptl0, *ptl1, *ptl2, *ptl3;
  73.     pte_t *newpt;
  74.  
  75.     ptl0 = (pte_t *) PA2KA((uintptr_t) as->genarch.page_table);
  76.  
  77.     if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT) {
  78.         newpt = (pte_t *)frame_alloc(PTL1_SIZE, FRAME_KA);
  79.         memsetb(newpt, FRAME_SIZE << PTL1_SIZE, 0);
  80.         SET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page), KA2PA(newpt));
  81.         SET_PTL1_FLAGS(ptl0, PTL0_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
  82.     }
  83.  
  84.     ptl1 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page)));
  85.  
  86.     if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT) {
  87.         newpt = (pte_t *)frame_alloc(PTL2_SIZE, FRAME_KA);
  88.         memsetb(newpt, FRAME_SIZE << PTL2_SIZE, 0);
  89.         SET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page), KA2PA(newpt));
  90.         SET_PTL2_FLAGS(ptl1, PTL1_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
  91.     }
  92.  
  93.     ptl2 = (pte_t *) PA2KA(GET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page)));
  94.  
  95.     if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT) {
  96.         newpt = (pte_t *)frame_alloc(PTL3_SIZE, FRAME_KA);
  97.         memsetb(newpt, FRAME_SIZE << PTL3_SIZE, 0);
  98.         SET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page), KA2PA(newpt));
  99.         SET_PTL3_FLAGS(ptl2, PTL2_INDEX(page), PAGE_PRESENT | PAGE_USER | PAGE_EXEC | PAGE_CACHEABLE | PAGE_WRITE);
  100.     }
  101.  
  102.     ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
  103.  
  104.     SET_FRAME_ADDRESS(ptl3, PTL3_INDEX(page), frame);
  105.     SET_FRAME_FLAGS(ptl3, PTL3_INDEX(page), flags);
  106. }
  107.  
  108. /** Remove mapping of page from hierarchical page tables.
  109.  *
  110.  * Remove any mapping of page within address space as.
  111.  * TLB shootdown should follow in order to make effects of
  112.  * this call visible.
  113.  *
  114.  * Empty page tables except PTL0 are freed.
  115.  *
  116.  * The page table must be locked and interrupts must be disabled.
  117.  *
  118.  * @param as Address space to wich page belongs.
  119.  * @param page Virtual address of the page to be demapped.
  120.  */
  121. void pt_mapping_remove(as_t *as, uintptr_t page)
  122. {
  123.     pte_t *ptl0, *ptl1, *ptl2, *ptl3;
  124.     bool empty = true;
  125.     int i;
  126.  
  127.     /*
  128.      * First, remove the mapping, if it exists.
  129.      */
  130.  
  131.     ptl0 = (pte_t *) PA2KA((uintptr_t) as->genarch.page_table);
  132.  
  133.     if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT)
  134.         return;
  135.  
  136.     ptl1 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page)));
  137.  
  138.     if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT)
  139.         return;
  140.  
  141.     ptl2 = (pte_t *) PA2KA(GET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page)));
  142.  
  143.     if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT)
  144.         return;
  145.  
  146.     ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
  147.  
  148.     /* Destroy the mapping. Setting to PAGE_NOT_PRESENT is not sufficient. */
  149.     memsetb(&ptl3[PTL3_INDEX(page)], sizeof(pte_t), 0);
  150.  
  151.     /*
  152.      * Second, free all empty tables along the way from PTL3 down to PTL0.
  153.      */
  154.    
  155.     /* check PTL3 */
  156.     for (i = 0; i < PTL3_ENTRIES; i++) {
  157.         if (PTE_VALID(&ptl3[i])) {
  158.             empty = false;
  159.             break;
  160.         }
  161.     }
  162.     if (empty) {
  163.         /*
  164.          * PTL3 is empty.
  165.          * Release the frame and remove PTL3 pointer from preceding table.
  166.          */
  167.         frame_free(KA2PA((uintptr_t) ptl3));
  168.         if (PTL2_ENTRIES)
  169.             memsetb(&ptl2[PTL2_INDEX(page)], sizeof(pte_t), 0);
  170.         else if (PTL1_ENTRIES)
  171.             memsetb(&ptl1[PTL1_INDEX(page)], sizeof(pte_t), 0);
  172.         else
  173.             memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
  174.     } else {
  175.         /*
  176.          * PTL3 is not empty.
  177.          * Therefore, there must be a path from PTL0 to PTL3 and
  178.          * thus nothing to free in higher levels.
  179.          */
  180.         return;
  181.     }
  182.    
  183.     /* check PTL2, empty is still true */
  184.     if (PTL2_ENTRIES) {
  185.         for (i = 0; i < PTL2_ENTRIES; i++) {
  186.             if (PTE_VALID(&ptl2[i])) {
  187.                 empty = false;
  188.                 break;
  189.             }
  190.         }
  191.         if (empty) {
  192.             /*
  193.              * PTL2 is empty.
  194.              * Release the frame and remove PTL2 pointer from preceding table.
  195.              */
  196.             frame_free(KA2PA((uintptr_t) ptl2));
  197.             if (PTL1_ENTRIES)
  198.                 memsetb(&ptl1[PTL1_INDEX(page)], sizeof(pte_t), 0);
  199.             else
  200.                 memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
  201.         }
  202.         else {
  203.             /*
  204.              * PTL2 is not empty.
  205.              * Therefore, there must be a path from PTL0 to PTL2 and
  206.              * thus nothing to free in higher levels.
  207.              */
  208.             return;
  209.         }
  210.     }
  211.  
  212.     /* check PTL1, empty is still true */
  213.     if (PTL1_ENTRIES) {
  214.         for (i = 0; i < PTL1_ENTRIES; i++) {
  215.             if (PTE_VALID(&ptl1[i])) {
  216.                 empty = false;
  217.                 break;
  218.             }
  219.         }
  220.         if (empty) {
  221.             /*
  222.              * PTL1 is empty.
  223.              * Release the frame and remove PTL1 pointer from preceding table.
  224.              */
  225.             frame_free(KA2PA((uintptr_t) ptl1));
  226.             memsetb(&ptl0[PTL0_INDEX(page)], sizeof(pte_t), 0);
  227.         }
  228.     }
  229.  
  230. }
  231.  
  232. /** Find mapping for virtual page in hierarchical page tables.
  233.  *
  234.  * Find mapping for virtual page.
  235.  *
  236.  * The page table must be locked and interrupts must be disabled.
  237.  *
  238.  * @param as Address space to which page belongs.
  239.  * @param page Virtual page.
  240.  *
  241.  * @return NULL if there is no such mapping; entry from PTL3 describing the mapping otherwise.
  242.  */
  243. pte_t *pt_mapping_find(as_t *as, uintptr_t page)
  244. {
  245.     pte_t *ptl0, *ptl1, *ptl2, *ptl3;
  246.  
  247.     ptl0 = (pte_t *) PA2KA((uintptr_t) as->genarch.page_table);
  248.  
  249.     if (GET_PTL1_FLAGS(ptl0, PTL0_INDEX(page)) & PAGE_NOT_PRESENT)
  250.         return NULL;
  251.  
  252.     ptl1 = (pte_t *) PA2KA(GET_PTL1_ADDRESS(ptl0, PTL0_INDEX(page)));
  253.  
  254.     if (GET_PTL2_FLAGS(ptl1, PTL1_INDEX(page)) & PAGE_NOT_PRESENT)
  255.         return NULL;
  256.  
  257.     ptl2 = (pte_t *) PA2KA(GET_PTL2_ADDRESS(ptl1, PTL1_INDEX(page)));
  258.  
  259.     if (GET_PTL3_FLAGS(ptl2, PTL2_INDEX(page)) & PAGE_NOT_PRESENT)
  260.         return NULL;
  261.  
  262.     ptl3 = (pte_t *) PA2KA(GET_PTL3_ADDRESS(ptl2, PTL2_INDEX(page)));
  263.  
  264.     return &ptl3[PTL3_INDEX(page)];
  265. }
  266.  
  267. /** @}
  268.  */
  269.