Ignore:
File:
1 edited

Legend:

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

    r55b77d9 r8f80c77  
    4343#include <mm/slab.h>
    4444#include <mm/page.h>
    45 #include <mm/reserve.h>
    4645#include <genarch/mm/page_pt.h>
    4746#include <genarch/mm/page_ht.h>
     
    5251#include <arch/barrier.h>
    5352
    54 static bool elf_create(as_area_t *);
    55 static bool elf_resize(as_area_t *, size_t);
    56 static void elf_share(as_area_t *);
    57 static void elf_destroy(as_area_t *);
    58 
    59 static int elf_page_fault(as_area_t *, uintptr_t, pf_access_t);
    60 static void elf_frame_free(as_area_t *, uintptr_t, uintptr_t);
     53#ifdef CONFIG_VIRT_IDX_DCACHE
     54#include <arch/mm/cache.h>
     55#endif
     56
     57static int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access);
     58static void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame);
     59static void elf_share(as_area_t *area);
    6160
    6261mem_backend_t elf_backend = {
    63         .create = elf_create,
    64         .resize = elf_resize,
    65         .share = elf_share,
    66         .destroy = elf_destroy,
    67 
    6862        .page_fault = elf_page_fault,
    6963        .frame_free = elf_frame_free,
     64        .share = elf_share
    7065};
    7166
    72 static size_t elf_nonanon_pages_get(as_area_t *area)
     67/** Service a page fault in the ELF backend address space area.
     68 *
     69 * The address space area and page tables must be already locked.
     70 *
     71 * @param area          Pointer to the address space area.
     72 * @param addr          Faulting virtual address.
     73 * @param access        Access mode that caused the fault (i.e.
     74 *                      read/write/exec).
     75 *
     76 * @return              AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK
     77 *                      on success (i.e. serviced).
     78 */
     79int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
     80{
     81        elf_header_t *elf = area->backend_data.elf;
     82        elf_segment_header_t *entry = area->backend_data.segment;
     83        btree_node_t *leaf;
     84        uintptr_t base, frame, page, start_anon;
     85        size_t i;
     86        bool dirty = false;
     87
     88        ASSERT(page_table_locked(AS));
     89        ASSERT(mutex_locked(&area->lock));
     90
     91        if (!as_area_check_access(area, access))
     92                return AS_PF_FAULT;
     93
     94        ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) &&
     95            (addr < entry->p_vaddr + entry->p_memsz));
     96        i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
     97        base = (uintptr_t)
     98            (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
     99
     100        /* Virtual address of faulting page*/
     101        page = ALIGN_DOWN(addr, PAGE_SIZE);
     102
     103        /* Virtual address of the end of initialized part of segment */
     104        start_anon = entry->p_vaddr + entry->p_filesz;
     105
     106        if (area->sh_info) {
     107                bool found = false;
     108
     109                /*
     110                 * The address space area is shared.
     111                 */
     112               
     113                mutex_lock(&area->sh_info->lock);
     114                frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
     115                    page - area->base, &leaf);
     116                if (!frame) {
     117                        unsigned int i;
     118
     119                        /*
     120                         * Workaround for valid NULL address.
     121                         */
     122
     123                        for (i = 0; i < leaf->keys; i++) {
     124                                if (leaf->key[i] == page - area->base) {
     125                                        found = true;
     126                                        break;
     127                                }
     128                        }
     129                }
     130                if (frame || found) {
     131                        frame_reference_add(ADDR2PFN(frame));
     132                        page_mapping_insert(AS, addr, frame,
     133                            as_area_get_flags(area));
     134                        if (!used_space_insert(area, page, 1))
     135                                panic("Cannot insert used space.");
     136                        mutex_unlock(&area->sh_info->lock);
     137                        return AS_PF_OK;
     138                }
     139        }
     140
     141        /*
     142         * The area is either not shared or the pagemap does not contain the
     143         * mapping.
     144         */
     145        if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
     146                /*
     147                 * Initialized portion of the segment. The memory is backed
     148                 * directly by the content of the ELF image. Pages are
     149                 * only copied if the segment is writable so that there
     150                 * can be more instantions of the same memory ELF image
     151                 * used at a time. Note that this could be later done
     152                 * as COW.
     153                 */
     154                if (entry->p_flags & PF_W) {
     155                        frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     156                        memcpy((void *) PA2KA(frame),
     157                            (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
     158                        if (entry->p_flags & PF_X) {
     159                                smc_coherence_block((void *) PA2KA(frame),
     160                                    FRAME_SIZE);
     161                        }
     162                        dirty = true;
     163                } else {
     164                        frame = KA2PA(base + i * FRAME_SIZE);
     165                }       
     166        } else if (page >= start_anon) {
     167                /*
     168                 * This is the uninitialized portion of the segment.
     169                 * It is not physically present in the ELF image.
     170                 * To resolve the situation, a frame must be allocated
     171                 * and cleared.
     172                 */
     173                frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     174                memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
     175                dirty = true;
     176        } else {
     177                size_t pad_lo, pad_hi;
     178                /*
     179                 * The mixed case.
     180                 *
     181                 * The middle part is backed by the ELF image and
     182                 * the lower and upper parts are anonymous memory.
     183                 * (The segment can be and often is shorter than 1 page).
     184                 */
     185                if (page < entry->p_vaddr)
     186                        pad_lo = entry->p_vaddr - page;
     187                else
     188                        pad_lo = 0;
     189
     190                if (start_anon < page + PAGE_SIZE)
     191                        pad_hi = page + PAGE_SIZE - start_anon;
     192                else
     193                        pad_hi = 0;
     194
     195                frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     196                memcpy((void *) (PA2KA(frame) + pad_lo),
     197                    (void *) (base + i * FRAME_SIZE + pad_lo),
     198                    FRAME_SIZE - pad_lo - pad_hi);
     199                if (entry->p_flags & PF_X) {
     200                        smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
     201                            FRAME_SIZE - pad_lo - pad_hi);
     202                }
     203                memsetb((void *) PA2KA(frame), pad_lo, 0);
     204                memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
     205                    0);
     206                dirty = true;
     207        }
     208
     209        if (dirty && area->sh_info) {
     210                frame_reference_add(ADDR2PFN(frame));
     211                btree_insert(&area->sh_info->pagemap, page - area->base,
     212                    (void *) frame, leaf);
     213        }
     214
     215        if (area->sh_info)
     216                mutex_unlock(&area->sh_info->lock);
     217
     218        page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
     219        if (!used_space_insert(area, page, 1))
     220                panic("Cannot insert used space.");
     221
     222        return AS_PF_OK;
     223}
     224
     225/** Free a frame that is backed by the ELF backend.
     226 *
     227 * The address space area and page tables must be already locked.
     228 *
     229 * @param area          Pointer to the address space area.
     230 * @param page          Page that is mapped to frame. Must be aligned to
     231 *                      PAGE_SIZE.
     232 * @param frame         Frame to be released.
     233 *
     234 */
     235void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
    73236{
    74237        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 
    88 bool 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 
    98 bool 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;
     238        uintptr_t start_anon;
     239
     240        ASSERT(page_table_locked(area->as));
     241        ASSERT(mutex_locked(&area->lock));
     242
     243        ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE));
     244        ASSERT(page < entry->p_vaddr + entry->p_memsz);
     245
     246        start_anon = entry->p_vaddr + entry->p_filesz;
     247
     248        if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
     249                if (entry->p_flags & PF_W) {
     250                        /*
     251                         * Free the frame with the copy of writable segment
     252                         * data.
     253                         */
     254                        frame_free(frame);
     255                }
     256        } else {
     257                /*
     258                 * The frame is either anonymous memory or the mixed case (i.e.
     259                 * lower part is backed by the ELF image and the upper is
     260                 * anonymous). In any case, a frame needs to be freed.
     261                 */
     262                frame_free(frame);
     263        }
    117264}
    118265
     
    139286         */
    140287        if (area->flags & AS_AREA_WRITE) {
    141                 node = list_get_instance(list_first(&area->used_space.leaf_list),
     288                node = list_get_instance(area->used_space.leaf_head.next,
    142289                    btree_node_t, leaf_link);
    143290        } else {
     
    153300         */
    154301        mutex_lock(&area->sh_info->lock);
    155         for (cur = &node->leaf_link; cur != &area->used_space.leaf_list.head;
     302        for (cur = &node->leaf_link; cur != &area->used_space.leaf_head;
    156303            cur = cur->next) {
    157304                unsigned int i;
     
    170317                        if (!(area->flags & AS_AREA_WRITE))
    171318                                if (base >= entry->p_vaddr &&
    172                                     base + P2SZ(count) <= start_anon)
     319                                    base + count * PAGE_SIZE <= start_anon)
    173320                                        continue;
    174321                       
     
    182329                                if (!(area->flags & AS_AREA_WRITE))
    183330                                        if (base >= entry->p_vaddr &&
    184                                             base + P2SZ(j + 1) <= start_anon)
     331                                            base + (j + 1) * PAGE_SIZE <=
     332                                            start_anon)
    185333                                                continue;
    186334                               
    187335                                page_table_lock(area->as, false);
    188336                                pte = page_mapping_find(area->as,
    189                                     base + P2SZ(j), false);
     337                                    base + j * PAGE_SIZE);
    190338                                ASSERT(pte && PTE_VALID(pte) &&
    191339                                    PTE_PRESENT(pte));
    192340                                btree_insert(&area->sh_info->pagemap,
    193                                     (base + P2SZ(j)) - area->base,
     341                                    (base + j * PAGE_SIZE) - area->base,
    194342                                    (void *) PTE_GET_FRAME(pte), NULL);
    195343                                page_table_unlock(area->as, false);
     
    204352}
    205353
    206 void 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 }
    213 
    214 /** Service a page fault in the ELF backend address space area.
    215  *
    216  * The address space area and page tables must be already locked.
    217  *
    218  * @param area          Pointer to the address space area.
    219  * @param addr          Faulting virtual address.
    220  * @param access        Access mode that caused the fault (i.e.
    221  *                      read/write/exec).
    222  *
    223  * @return              AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK
    224  *                      on success (i.e. serviced).
    225  */
    226 int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
    227 {
    228         elf_header_t *elf = area->backend_data.elf;
    229         elf_segment_header_t *entry = area->backend_data.segment;
    230         btree_node_t *leaf;
    231         uintptr_t base, frame, page, start_anon;
    232         size_t i;
    233         bool dirty = false;
    234 
    235         ASSERT(page_table_locked(AS));
    236         ASSERT(mutex_locked(&area->lock));
    237 
    238         if (!as_area_check_access(area, access))
    239                 return AS_PF_FAULT;
    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        
    247         i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
    248         base = (uintptr_t)
    249             (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
    250 
    251         /* Virtual address of faulting page*/
    252         page = ALIGN_DOWN(addr, PAGE_SIZE);
    253 
    254         /* Virtual address of the end of initialized part of segment */
    255         start_anon = entry->p_vaddr + entry->p_filesz;
    256 
    257         if (area->sh_info) {
    258                 bool found = false;
    259 
    260                 /*
    261                  * The address space area is shared.
    262                  */
    263                
    264                 mutex_lock(&area->sh_info->lock);
    265                 frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
    266                     page - area->base, &leaf);
    267                 if (!frame) {
    268                         unsigned int i;
    269 
    270                         /*
    271                          * Workaround for valid NULL address.
    272                          */
    273 
    274                         for (i = 0; i < leaf->keys; i++) {
    275                                 if (leaf->key[i] == page - area->base) {
    276                                         found = true;
    277                                         break;
    278                                 }
    279                         }
    280                 }
    281                 if (frame || found) {
    282                         frame_reference_add(ADDR2PFN(frame));
    283                         page_mapping_insert(AS, addr, frame,
    284                             as_area_get_flags(area));
    285                         if (!used_space_insert(area, page, 1))
    286                                 panic("Cannot insert used space.");
    287                         mutex_unlock(&area->sh_info->lock);
    288                         return AS_PF_OK;
    289                 }
    290         }
    291 
    292         /*
    293          * The area is either not shared or the pagemap does not contain the
    294          * mapping.
    295          */
    296         if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
    297                 /*
    298                  * Initialized portion of the segment. The memory is backed
    299                  * directly by the content of the ELF image. Pages are
    300                  * only copied if the segment is writable so that there
    301                  * can be more instantions of the same memory ELF image
    302                  * used at a time. Note that this could be later done
    303                  * as COW.
    304                  */
    305                 if (entry->p_flags & PF_W) {
    306                         frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0);
    307                         memcpy((void *) PA2KA(frame),
    308                             (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
    309                         if (entry->p_flags & PF_X) {
    310                                 smc_coherence_block((void *) PA2KA(frame),
    311                                     FRAME_SIZE);
    312                         }
    313                         dirty = true;
    314                 } else {
    315                         frame = KA2PA(base + i * FRAME_SIZE);
    316                 }       
    317         } else if (page >= start_anon) {
    318                 /*
    319                  * This is the uninitialized portion of the segment.
    320                  * It is not physically present in the ELF image.
    321                  * To resolve the situation, a frame must be allocated
    322                  * and cleared.
    323                  */
    324                 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    325                 memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
    326                 dirty = true;
    327         } else {
    328                 size_t pad_lo, pad_hi;
    329                 /*
    330                  * The mixed case.
    331                  *
    332                  * The middle part is backed by the ELF image and
    333                  * the lower and upper parts are anonymous memory.
    334                  * (The segment can be and often is shorter than 1 page).
    335                  */
    336                 if (page < entry->p_vaddr)
    337                         pad_lo = entry->p_vaddr - page;
    338                 else
    339                         pad_lo = 0;
    340 
    341                 if (start_anon < page + PAGE_SIZE)
    342                         pad_hi = page + PAGE_SIZE - start_anon;
    343                 else
    344                         pad_hi = 0;
    345 
    346                 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    347                 memcpy((void *) (PA2KA(frame) + pad_lo),
    348                     (void *) (base + i * FRAME_SIZE + pad_lo),
    349                     FRAME_SIZE - pad_lo - pad_hi);
    350                 if (entry->p_flags & PF_X) {
    351                         smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
    352                             FRAME_SIZE - pad_lo - pad_hi);
    353                 }
    354                 memsetb((void *) PA2KA(frame), pad_lo, 0);
    355                 memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
    356                     0);
    357                 dirty = true;
    358         }
    359 
    360         if (dirty && area->sh_info) {
    361                 frame_reference_add(ADDR2PFN(frame));
    362                 btree_insert(&area->sh_info->pagemap, page - area->base,
    363                     (void *) frame, leaf);
    364         }
    365 
    366         if (area->sh_info)
    367                 mutex_unlock(&area->sh_info->lock);
    368 
    369         page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
    370         if (!used_space_insert(area, page, 1))
    371                 panic("Cannot insert used space.");
    372 
    373         return AS_PF_OK;
    374 }
    375 
    376 /** Free a frame that is backed by the ELF backend.
    377  *
    378  * The address space area and page tables must be already locked.
    379  *
    380  * @param area          Pointer to the address space area.
    381  * @param page          Page that is mapped to frame. Must be aligned to
    382  *                      PAGE_SIZE.
    383  * @param frame         Frame to be released.
    384  *
    385  */
    386 void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
    387 {
    388         elf_segment_header_t *entry = area->backend_data.segment;
    389         uintptr_t start_anon;
    390 
    391         ASSERT(page_table_locked(area->as));
    392         ASSERT(mutex_locked(&area->lock));
    393 
    394         ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE));
    395         ASSERT(page < entry->p_vaddr + entry->p_memsz);
    396 
    397         start_anon = entry->p_vaddr + entry->p_filesz;
    398 
    399         if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
    400                 if (entry->p_flags & PF_W) {
    401                         /*
    402                          * Free the frame with the copy of writable segment
    403                          * data.
    404                          */
    405                         frame_free_noreserve(frame);
    406                 }
    407         } else {
    408                 /*
    409                  * The frame is either anonymous memory or the mixed case (i.e.
    410                  * lower part is backed by the ELF image and the upper is
    411                  * anonymous). In any case, a frame needs to be freed.
    412                  */
    413                 frame_free_noreserve(frame);
    414         }
    415 }
    416 
    417354/** @}
    418355 */
Note: See TracChangeset for help on using the changeset viewer.