Changeset c98e6ee in mainline for kernel/generic/src/mm/as.c
- Timestamp:
- 2008-07-08T16:05:45Z (17 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f93f168
- Parents:
- b7f9087
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/mm/as.c
rb7f9087 rc98e6ee 772 772 } 773 773 774 /** Change adress area flags. 775 * 776 * The idea is to have the same data, but with a different access mode. 777 * This is needed e.g. for writing code into memory and then executing it. 778 * In order for this to work properly, this may copy the data 779 * into private anonymous memory (unless it's already there). 780 * 781 * @param as Address space. 782 * @param flags Flags of the area memory. 783 * @param address Address withing the area to be changed. 784 * 785 * @return Zero on success or a value from @ref errno.h on failure. 786 */ 787 int as_area_change_flags(as_t *as, int flags, uintptr_t address) 788 { 789 as_area_t *area; 790 uintptr_t base; 791 link_t *cur; 792 ipl_t ipl; 793 int page_flags; 794 uintptr_t *old_frame; 795 index_t frame_idx; 796 count_t used_pages; 797 798 /* Flags for the new memory mapping */ 799 page_flags = area_flags_to_page_flags(flags); 800 801 ipl = interrupts_disable(); 802 mutex_lock(&as->lock); 803 804 area = find_area_and_lock(as, address); 805 if (!area) { 806 mutex_unlock(&as->lock); 807 interrupts_restore(ipl); 808 return ENOENT; 809 } 810 811 if (area->sh_info || area->backend != &anon_backend) { 812 /* Copying shared areas not supported yet */ 813 /* Copying non-anonymous memory not supported yet */ 814 mutex_unlock(&area->lock); 815 mutex_unlock(&as->lock); 816 interrupts_restore(ipl); 817 return ENOTSUP; 818 } 819 820 base = area->base; 821 822 /* 823 * Compute total number of used pages in the used_space B+tree 824 */ 825 used_pages = 0; 826 827 for (cur = area->used_space.leaf_head.next; 828 cur != &area->used_space.leaf_head; cur = cur->next) { 829 btree_node_t *node; 830 unsigned int i; 831 832 node = list_get_instance(cur, btree_node_t, leaf_link); 833 for (i = 0; i < node->keys; i++) { 834 used_pages += (count_t) node->value[i]; 835 } 836 } 837 838 /* An array for storing frame numbers */ 839 old_frame = malloc(used_pages * sizeof(uintptr_t), 0); 840 841 /* 842 * Start TLB shootdown sequence. 843 */ 844 tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base, area->pages); 845 846 /* 847 * Remove used pages from page tables and remember their frame 848 * numbers. 849 */ 850 frame_idx = 0; 851 852 for (cur = area->used_space.leaf_head.next; 853 cur != &area->used_space.leaf_head; cur = cur->next) { 854 btree_node_t *node; 855 unsigned int i; 856 857 node = list_get_instance(cur, btree_node_t, leaf_link); 858 for (i = 0; i < node->keys; i++) { 859 uintptr_t b = node->key[i]; 860 count_t j; 861 pte_t *pte; 862 863 for (j = 0; j < (count_t) node->value[i]; j++) { 864 page_table_lock(as, false); 865 pte = page_mapping_find(as, b + j * PAGE_SIZE); 866 ASSERT(pte && PTE_VALID(pte) && 867 PTE_PRESENT(pte)); 868 old_frame[frame_idx++] = PTE_GET_FRAME(pte); 869 870 /* Remove old mapping */ 871 page_mapping_remove(as, b + j * PAGE_SIZE); 872 page_table_unlock(as, false); 873 } 874 } 875 } 876 877 /* 878 * Finish TLB shootdown sequence. 879 */ 880 881 tlb_invalidate_pages(as->asid, area->base, area->pages); 882 /* 883 * Invalidate potential software translation caches (e.g. TSB on 884 * sparc64). 885 */ 886 as_invalidate_translation_cache(as, area->base, area->pages); 887 tlb_shootdown_finalize(); 888 889 /* 890 * Map pages back in with new flags. This step is kept separate 891 * so that there's no instant when the memory area could be 892 * accesed with both the old and the new flags at once. 893 */ 894 frame_idx = 0; 895 896 for (cur = area->used_space.leaf_head.next; 897 cur != &area->used_space.leaf_head; cur = cur->next) { 898 btree_node_t *node; 899 unsigned int i; 900 901 node = list_get_instance(cur, btree_node_t, leaf_link); 902 for (i = 0; i < node->keys; i++) { 903 uintptr_t b = node->key[i]; 904 count_t j; 905 906 for (j = 0; j < (count_t) node->value[i]; j++) { 907 page_table_lock(as, false); 908 909 /* Insert the new mapping */ 910 page_mapping_insert(as, b + j * PAGE_SIZE, 911 old_frame[frame_idx++], page_flags); 912 913 page_table_unlock(as, false); 914 } 915 } 916 } 917 918 free(old_frame); 919 920 mutex_unlock(&area->lock); 921 mutex_unlock(&as->lock); 922 interrupts_restore(ipl); 923 924 return 0; 925 } 926 927 774 928 /** Handle page fault within the current address space. 775 929 * … … 1767 1921 } 1768 1922 1923 /** Wrapper for as_area_change_flags(). */ 1924 unative_t sys_as_area_change_flags(uintptr_t address, int flags) 1925 { 1926 return (unative_t) as_area_change_flags(AS, flags, address); 1927 } 1928 1769 1929 /** Wrapper for as_area_destroy(). */ 1770 1930 unative_t sys_as_area_destroy(uintptr_t address)
Note:
See TracChangeset
for help on using the changeset viewer.