Ignore:
File:
1 edited

Legend:

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

    r8f80c77 r55b77d9  
    4343#include <mm/slab.h>
    4444#include <mm/page.h>
     45#include <mm/reserve.h>
    4546#include <genarch/mm/page_pt.h>
    4647#include <genarch/mm/page_ht.h>
     
    5152#include <arch/barrier.h>
    5253
    53 #ifdef CONFIG_VIRT_IDX_DCACHE
    54 #include <arch/mm/cache.h>
    55 #endif
    56 
    57 static int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access);
    58 static void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame);
    59 static void elf_share(as_area_t *area);
     54static bool elf_create(as_area_t *);
     55static bool elf_resize(as_area_t *, size_t);
     56static void elf_share(as_area_t *);
     57static void elf_destroy(as_area_t *);
     58
     59static int elf_page_fault(as_area_t *, uintptr_t, pf_access_t);
     60static void elf_frame_free(as_area_t *, uintptr_t, uintptr_t);
    6061
    6162mem_backend_t elf_backend = {
     63        .create = elf_create,
     64        .resize = elf_resize,
     65        .share = elf_share,
     66        .destroy = elf_destroy,
     67
    6268        .page_fault = elf_page_fault,
    6369        .frame_free = elf_frame_free,
    64         .share = elf_share
    6570};
     71
     72static size_t elf_nonanon_pages_get(as_area_t *area)
     73{
     74        elf_segment_header_t *entry = area->backend_data.segment;
     75        uintptr_t first = ALIGN_UP(entry->p_vaddr, PAGE_SIZE);
     76        uintptr_t last = ALIGN_DOWN(entry->p_vaddr + entry->p_filesz,
     77            PAGE_SIZE);
     78
     79        if (entry->p_flags & PF_W)
     80                return 0;
     81
     82        if (last < first)
     83                return 0;
     84
     85        return last - first;
     86}
     87
     88bool elf_create(as_area_t *area)
     89{
     90        size_t nonanon_pages = elf_nonanon_pages_get(area);
     91
     92        if (area->pages <= nonanon_pages)
     93                return true;
     94       
     95        return reserve_try_alloc(area->pages - nonanon_pages);
     96}
     97
     98bool elf_resize(as_area_t *area, size_t new_pages)
     99{
     100        size_t nonanon_pages = elf_nonanon_pages_get(area);
     101
     102        if (new_pages > area->pages) {
     103                /* The area is growing. */
     104                if (area->pages >= nonanon_pages)
     105                        return reserve_try_alloc(new_pages - area->pages);
     106                else if (new_pages > nonanon_pages)
     107                        return reserve_try_alloc(new_pages - nonanon_pages);
     108        } else if (new_pages < area->pages) {
     109                /* The area is shrinking. */
     110                if (new_pages >= nonanon_pages)
     111                        reserve_free(area->pages - new_pages);
     112                else if (area->pages > nonanon_pages)
     113                        reserve_free(nonanon_pages - new_pages);
     114        }
     115       
     116        return true;
     117}
     118
     119/** Share ELF image backed address space area.
     120 *
     121 * If the area is writable, then all mapped pages are duplicated in the pagemap.
     122 * Otherwise only portions of the area that are not backed by the ELF image
     123 * are put into the pagemap.
     124 *
     125 * @param area          Address space area.
     126 */
     127void elf_share(as_area_t *area)
     128{
     129        elf_segment_header_t *entry = area->backend_data.segment;
     130        link_t *cur;
     131        btree_node_t *leaf, *node;
     132        uintptr_t start_anon = entry->p_vaddr + entry->p_filesz;
     133
     134        ASSERT(mutex_locked(&area->as->lock));
     135        ASSERT(mutex_locked(&area->lock));
     136
     137        /*
     138         * Find the node in which to start linear search.
     139         */
     140        if (area->flags & AS_AREA_WRITE) {
     141                node = list_get_instance(list_first(&area->used_space.leaf_list),
     142                    btree_node_t, leaf_link);
     143        } else {
     144                (void) btree_search(&area->sh_info->pagemap, start_anon, &leaf);
     145                node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap,
     146                    leaf);
     147                if (!node)
     148                        node = leaf;
     149        }
     150
     151        /*
     152         * Copy used anonymous portions of the area to sh_info's page map.
     153         */
     154        mutex_lock(&area->sh_info->lock);
     155        for (cur = &node->leaf_link; cur != &area->used_space.leaf_list.head;
     156            cur = cur->next) {
     157                unsigned int i;
     158               
     159                node = list_get_instance(cur, btree_node_t, leaf_link);
     160               
     161                for (i = 0; i < node->keys; i++) {
     162                        uintptr_t base = node->key[i];
     163                        size_t count = (size_t) node->value[i];
     164                        unsigned int j;
     165                       
     166                        /*
     167                         * Skip read-only areas of used space that are backed
     168                         * by the ELF image.
     169                         */
     170                        if (!(area->flags & AS_AREA_WRITE))
     171                                if (base >= entry->p_vaddr &&
     172                                    base + P2SZ(count) <= start_anon)
     173                                        continue;
     174                       
     175                        for (j = 0; j < count; j++) {
     176                                pte_t *pte;
     177                       
     178                                /*
     179                                 * Skip read-only pages that are backed by the
     180                                 * ELF image.
     181                                 */
     182                                if (!(area->flags & AS_AREA_WRITE))
     183                                        if (base >= entry->p_vaddr &&
     184                                            base + P2SZ(j + 1) <= start_anon)
     185                                                continue;
     186                               
     187                                page_table_lock(area->as, false);
     188                                pte = page_mapping_find(area->as,
     189                                    base + P2SZ(j), false);
     190                                ASSERT(pte && PTE_VALID(pte) &&
     191                                    PTE_PRESENT(pte));
     192                                btree_insert(&area->sh_info->pagemap,
     193                                    (base + P2SZ(j)) - area->base,
     194                                    (void *) PTE_GET_FRAME(pte), NULL);
     195                                page_table_unlock(area->as, false);
     196
     197                                pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte));
     198                                frame_reference_add(pfn);
     199                        }
     200                               
     201                }
     202        }
     203        mutex_unlock(&area->sh_info->lock);
     204}
     205
     206void elf_destroy(as_area_t *area)
     207{
     208        size_t nonanon_pages = elf_nonanon_pages_get(area);
     209
     210        if (area->pages > nonanon_pages)
     211                reserve_free(area->pages - nonanon_pages);
     212}
    66213
    67214/** Service a page fault in the ELF backend address space area.
     
    91238        if (!as_area_check_access(area, access))
    92239                return AS_PF_FAULT;
    93 
    94         ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) &&
    95             (addr < entry->p_vaddr + entry->p_memsz));
     240       
     241        if (addr < ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE))
     242                return AS_PF_FAULT;
     243       
     244        if (addr >= entry->p_vaddr + entry->p_memsz)
     245                return AS_PF_FAULT;
     246       
    96247        i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
    97248        base = (uintptr_t)
     
    153304                 */
    154305                if (entry->p_flags & PF_W) {
    155                         frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     306                        frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0);
    156307                        memcpy((void *) PA2KA(frame),
    157308                            (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
     
    171322                 * and cleared.
    172323                 */
    173                 frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     324                frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    174325                memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
    175326                dirty = true;
     
    193344                        pad_hi = 0;
    194345
    195                 frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     346                frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    196347                memcpy((void *) (PA2KA(frame) + pad_lo),
    197348                    (void *) (base + i * FRAME_SIZE + pad_lo),
     
    252403                         * data.
    253404                         */
    254                         frame_free(frame);
     405                        frame_free_noreserve(frame);
    255406                }
    256407        } else {
     
    260411                 * anonymous). In any case, a frame needs to be freed.
    261412                 */
    262                 frame_free(frame);
    263         }
    264 }
    265 
    266 /** Share ELF image backed address space area.
    267  *
    268  * If the area is writable, then all mapped pages are duplicated in the pagemap.
    269  * Otherwise only portions of the area that are not backed by the ELF image
    270  * are put into the pagemap.
    271  *
    272  * @param area          Address space area.
    273  */
    274 void elf_share(as_area_t *area)
    275 {
    276         elf_segment_header_t *entry = area->backend_data.segment;
    277         link_t *cur;
    278         btree_node_t *leaf, *node;
    279         uintptr_t start_anon = entry->p_vaddr + entry->p_filesz;
    280 
    281         ASSERT(mutex_locked(&area->as->lock));
    282         ASSERT(mutex_locked(&area->lock));
    283 
    284         /*
    285          * Find the node in which to start linear search.
    286          */
    287         if (area->flags & AS_AREA_WRITE) {
    288                 node = list_get_instance(area->used_space.leaf_head.next,
    289                     btree_node_t, leaf_link);
    290         } else {
    291                 (void) btree_search(&area->sh_info->pagemap, start_anon, &leaf);
    292                 node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap,
    293                     leaf);
    294                 if (!node)
    295                         node = leaf;
    296         }
    297 
    298         /*
    299          * Copy used anonymous portions of the area to sh_info's page map.
    300          */
    301         mutex_lock(&area->sh_info->lock);
    302         for (cur = &node->leaf_link; cur != &area->used_space.leaf_head;
    303             cur = cur->next) {
    304                 unsigned int i;
    305                
    306                 node = list_get_instance(cur, btree_node_t, leaf_link);
    307                
    308                 for (i = 0; i < node->keys; i++) {
    309                         uintptr_t base = node->key[i];
    310                         size_t count = (size_t) node->value[i];
    311                         unsigned int j;
    312                        
    313                         /*
    314                          * Skip read-only areas of used space that are backed
    315                          * by the ELF image.
    316                          */
    317                         if (!(area->flags & AS_AREA_WRITE))
    318                                 if (base >= entry->p_vaddr &&
    319                                     base + count * PAGE_SIZE <= start_anon)
    320                                         continue;
    321                        
    322                         for (j = 0; j < count; j++) {
    323                                 pte_t *pte;
    324                        
    325                                 /*
    326                                  * Skip read-only pages that are backed by the
    327                                  * ELF image.
    328                                  */
    329                                 if (!(area->flags & AS_AREA_WRITE))
    330                                         if (base >= entry->p_vaddr &&
    331                                             base + (j + 1) * PAGE_SIZE <=
    332                                             start_anon)
    333                                                 continue;
    334                                
    335                                 page_table_lock(area->as, false);
    336                                 pte = page_mapping_find(area->as,
    337                                     base + j * PAGE_SIZE);
    338                                 ASSERT(pte && PTE_VALID(pte) &&
    339                                     PTE_PRESENT(pte));
    340                                 btree_insert(&area->sh_info->pagemap,
    341                                     (base + j * PAGE_SIZE) - area->base,
    342                                     (void *) PTE_GET_FRAME(pte), NULL);
    343                                 page_table_unlock(area->as, false);
    344 
    345                                 pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte));
    346                                 frame_reference_add(pfn);
    347                         }
    348                                
    349                 }
    350         }
    351         mutex_unlock(&area->sh_info->lock);
     413                frame_free_noreserve(frame);
     414        }
    352415}
    353416
Note: See TracChangeset for help on using the changeset viewer.