Changeset c98e6ee in mainline for kernel/generic/src/mm/as.c


Ignore:
Timestamp:
2008-07-08T16:05:45Z (17 years ago)
Author:
Jiri Svoboda <jirik.svoboda@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f93f168
Parents:
b7f9087
Message:

Merge program-loader related stuff from dynload branch to trunk. (huge)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/as.c

    rb7f9087 rc98e6ee  
    772772}
    773773
     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 */
     787int 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
    774928/** Handle page fault within the current address space.
    775929 *
     
    17671921}
    17681922
     1923/** Wrapper for as_area_change_flags(). */
     1924unative_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
    17691929/** Wrapper for as_area_destroy(). */
    17701930unative_t sys_as_area_destroy(uintptr_t address)
Note: See TracChangeset for help on using the changeset viewer.