Rev 3186 | Rev 3240 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3186 | Rev 3222 | ||
---|---|---|---|
Line 769... | Line 769... | ||
769 | return false; |
769 | return false; |
770 | 770 | ||
771 | return true; |
771 | return true; |
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 | /** Handle page fault within the current address space. |
928 | /** Handle page fault within the current address space. |
775 | * |
929 | * |
776 | * This is the high-level page fault handler. It decides |
930 | * This is the high-level page fault handler. It decides |
777 | * whether the page fault can be resolved by any backend |
931 | * whether the page fault can be resolved by any backend |
778 | * and if so, it invokes the backend to resolve the page |
932 | * and if so, it invokes the backend to resolve the page |
Line 1764... | Line 1918... | ||
1764 | unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags) |
1918 | unative_t sys_as_area_resize(uintptr_t address, size_t size, int flags) |
1765 | { |
1919 | { |
1766 | return (unative_t) as_area_resize(AS, address, size, 0); |
1920 | return (unative_t) as_area_resize(AS, address, size, 0); |
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 | /** Wrapper for as_area_destroy(). */ |
1929 | /** Wrapper for as_area_destroy(). */ |
1770 | unative_t sys_as_area_destroy(uintptr_t address) |
1930 | unative_t sys_as_area_destroy(uintptr_t address) |
1771 | { |
1931 | { |
1772 | return (unative_t) as_area_destroy(AS, address); |
1932 | return (unative_t) as_area_destroy(AS, address); |
1773 | } |
1933 | } |