Subversion Repositories HelenOS-historic

Rev

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