Ignore:
File:
1 edited

Legend:

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

    r8f6c6264 r917a8c8  
    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        if (addr < ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE))
     95                return AS_PF_FAULT;
     96       
     97        if (addr >= entry->p_vaddr + entry->p_memsz)
     98                return AS_PF_FAULT;
     99       
     100        i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
     101        base = (uintptr_t)
     102            (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
     103
     104        /* Virtual address of faulting page*/
     105        page = ALIGN_DOWN(addr, PAGE_SIZE);
     106
     107        /* Virtual address of the end of initialized part of segment */
     108        start_anon = entry->p_vaddr + entry->p_filesz;
     109
     110        if (area->sh_info) {
     111                bool found = false;
     112
     113                /*
     114                 * The address space area is shared.
     115                 */
     116               
     117                mutex_lock(&area->sh_info->lock);
     118                frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
     119                    page - area->base, &leaf);
     120                if (!frame) {
     121                        unsigned int i;
     122
     123                        /*
     124                         * Workaround for valid NULL address.
     125                         */
     126
     127                        for (i = 0; i < leaf->keys; i++) {
     128                                if (leaf->key[i] == page - area->base) {
     129                                        found = true;
     130                                        break;
     131                                }
     132                        }
     133                }
     134                if (frame || found) {
     135                        frame_reference_add(ADDR2PFN(frame));
     136                        page_mapping_insert(AS, addr, frame,
     137                            as_area_get_flags(area));
     138                        if (!used_space_insert(area, page, 1))
     139                                panic("Cannot insert used space.");
     140                        mutex_unlock(&area->sh_info->lock);
     141                        return AS_PF_OK;
     142                }
     143        }
     144
     145        /*
     146         * The area is either not shared or the pagemap does not contain the
     147         * mapping.
     148         */
     149        if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
     150                /*
     151                 * Initialized portion of the segment. The memory is backed
     152                 * directly by the content of the ELF image. Pages are
     153                 * only copied if the segment is writable so that there
     154                 * can be more instantions of the same memory ELF image
     155                 * used at a time. Note that this could be later done
     156                 * as COW.
     157                 */
     158                if (entry->p_flags & PF_W) {
     159                        frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     160                        memcpy((void *) PA2KA(frame),
     161                            (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
     162                        if (entry->p_flags & PF_X) {
     163                                smc_coherence_block((void *) PA2KA(frame),
     164                                    FRAME_SIZE);
     165                        }
     166                        dirty = true;
     167                } else {
     168                        frame = KA2PA(base + i * FRAME_SIZE);
     169                }       
     170        } else if (page >= start_anon) {
     171                /*
     172                 * This is the uninitialized portion of the segment.
     173                 * It is not physically present in the ELF image.
     174                 * To resolve the situation, a frame must be allocated
     175                 * and cleared.
     176                 */
     177                frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     178                memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
     179                dirty = true;
     180        } else {
     181                size_t pad_lo, pad_hi;
     182                /*
     183                 * The mixed case.
     184                 *
     185                 * The middle part is backed by the ELF image and
     186                 * the lower and upper parts are anonymous memory.
     187                 * (The segment can be and often is shorter than 1 page).
     188                 */
     189                if (page < entry->p_vaddr)
     190                        pad_lo = entry->p_vaddr - page;
     191                else
     192                        pad_lo = 0;
     193
     194                if (start_anon < page + PAGE_SIZE)
     195                        pad_hi = page + PAGE_SIZE - start_anon;
     196                else
     197                        pad_hi = 0;
     198
     199                frame = (uintptr_t)frame_alloc(ONE_FRAME, 0);
     200                memcpy((void *) (PA2KA(frame) + pad_lo),
     201                    (void *) (base + i * FRAME_SIZE + pad_lo),
     202                    FRAME_SIZE - pad_lo - pad_hi);
     203                if (entry->p_flags & PF_X) {
     204                        smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
     205                            FRAME_SIZE - pad_lo - pad_hi);
     206                }
     207                memsetb((void *) PA2KA(frame), pad_lo, 0);
     208                memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
     209                    0);
     210                dirty = true;
     211        }
     212
     213        if (dirty && area->sh_info) {
     214                frame_reference_add(ADDR2PFN(frame));
     215                btree_insert(&area->sh_info->pagemap, page - area->base,
     216                    (void *) frame, leaf);
     217        }
     218
     219        if (area->sh_info)
     220                mutex_unlock(&area->sh_info->lock);
     221
     222        page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
     223        if (!used_space_insert(area, page, 1))
     224                panic("Cannot insert used space.");
     225
     226        return AS_PF_OK;
     227}
     228
     229/** Free a frame that is backed by the ELF backend.
     230 *
     231 * The address space area and page tables must be already locked.
     232 *
     233 * @param area          Pointer to the address space area.
     234 * @param page          Page that is mapped to frame. Must be aligned to
     235 *                      PAGE_SIZE.
     236 * @param frame         Frame to be released.
     237 *
     238 */
     239void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
    73240{
    74241        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;
     242        uintptr_t start_anon;
     243
     244        ASSERT(page_table_locked(area->as));
     245        ASSERT(mutex_locked(&area->lock));
     246
     247        ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE));
     248        ASSERT(page < entry->p_vaddr + entry->p_memsz);
     249
     250        start_anon = entry->p_vaddr + entry->p_filesz;
     251
     252        if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
     253                if (entry->p_flags & PF_W) {
     254                        /*
     255                         * Free the frame with the copy of writable segment
     256                         * data.
     257                         */
     258                        frame_free(frame);
     259                }
     260        } else {
     261                /*
     262                 * The frame is either anonymous memory or the mixed case (i.e.
     263                 * lower part is backed by the ELF image and the upper is
     264                 * anonymous). In any case, a frame needs to be freed.
     265                 */
     266                frame_free(frame);
     267        }
    117268}
    118269
     
    205356}
    206357
    207 void elf_destroy(as_area_t *area)
    208 {
    209         size_t nonanon_pages = elf_nonanon_pages_get(area);
    210 
    211         if (area->pages > nonanon_pages)
    212                 reserve_free(area->pages - nonanon_pages);
    213 }
    214 
    215 /** Service a page fault in the ELF backend address space area.
    216  *
    217  * The address space area and page tables must be already locked.
    218  *
    219  * @param area          Pointer to the address space area.
    220  * @param addr          Faulting virtual address.
    221  * @param access        Access mode that caused the fault (i.e.
    222  *                      read/write/exec).
    223  *
    224  * @return              AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK
    225  *                      on success (i.e. serviced).
    226  */
    227 int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
    228 {
    229         elf_header_t *elf = area->backend_data.elf;
    230         elf_segment_header_t *entry = area->backend_data.segment;
    231         btree_node_t *leaf;
    232         uintptr_t base, frame, page, start_anon;
    233         size_t i;
    234         bool dirty = false;
    235 
    236         ASSERT(page_table_locked(AS));
    237         ASSERT(mutex_locked(&area->lock));
    238 
    239         if (!as_area_check_access(area, access))
    240                 return AS_PF_FAULT;
    241        
    242         if (addr < ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE))
    243                 return AS_PF_FAULT;
    244        
    245         if (addr >= entry->p_vaddr + entry->p_memsz)
    246                 return AS_PF_FAULT;
    247        
    248         i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;
    249         base = (uintptr_t)
    250             (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));
    251 
    252         /* Virtual address of faulting page*/
    253         page = ALIGN_DOWN(addr, PAGE_SIZE);
    254 
    255         /* Virtual address of the end of initialized part of segment */
    256         start_anon = entry->p_vaddr + entry->p_filesz;
    257 
    258         if (area->sh_info) {
    259                 bool found = false;
    260 
    261                 /*
    262                  * The address space area is shared.
    263                  */
    264                
    265                 mutex_lock(&area->sh_info->lock);
    266                 frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
    267                     page - area->base, &leaf);
    268                 if (!frame) {
    269                         unsigned int i;
    270 
    271                         /*
    272                          * Workaround for valid NULL address.
    273                          */
    274 
    275                         for (i = 0; i < leaf->keys; i++) {
    276                                 if (leaf->key[i] == page - area->base) {
    277                                         found = true;
    278                                         break;
    279                                 }
    280                         }
    281                 }
    282                 if (frame || found) {
    283                         frame_reference_add(ADDR2PFN(frame));
    284                         page_mapping_insert(AS, addr, frame,
    285                             as_area_get_flags(area));
    286                         if (!used_space_insert(area, page, 1))
    287                                 panic("Cannot insert used space.");
    288                         mutex_unlock(&area->sh_info->lock);
    289                         return AS_PF_OK;
    290                 }
    291         }
    292 
    293         /*
    294          * The area is either not shared or the pagemap does not contain the
    295          * mapping.
    296          */
    297         if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
    298                 /*
    299                  * Initialized portion of the segment. The memory is backed
    300                  * directly by the content of the ELF image. Pages are
    301                  * only copied if the segment is writable so that there
    302                  * can be more instantions of the same memory ELF image
    303                  * used at a time. Note that this could be later done
    304                  * as COW.
    305                  */
    306                 if (entry->p_flags & PF_W) {
    307                         frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0);
    308                         memcpy((void *) PA2KA(frame),
    309                             (void *) (base + i * FRAME_SIZE), FRAME_SIZE);
    310                         if (entry->p_flags & PF_X) {
    311                                 smc_coherence_block((void *) PA2KA(frame),
    312                                     FRAME_SIZE);
    313                         }
    314                         dirty = true;
    315                 } else {
    316                         frame = KA2PA(base + i * FRAME_SIZE);
    317                 }       
    318         } else if (page >= start_anon) {
    319                 /*
    320                  * This is the uninitialized portion of the segment.
    321                  * It is not physically present in the ELF image.
    322                  * To resolve the situation, a frame must be allocated
    323                  * and cleared.
    324                  */
    325                 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    326                 memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);
    327                 dirty = true;
    328         } else {
    329                 size_t pad_lo, pad_hi;
    330                 /*
    331                  * The mixed case.
    332                  *
    333                  * The middle part is backed by the ELF image and
    334                  * the lower and upper parts are anonymous memory.
    335                  * (The segment can be and often is shorter than 1 page).
    336                  */
    337                 if (page < entry->p_vaddr)
    338                         pad_lo = entry->p_vaddr - page;
    339                 else
    340                         pad_lo = 0;
    341 
    342                 if (start_anon < page + PAGE_SIZE)
    343                         pad_hi = page + PAGE_SIZE - start_anon;
    344                 else
    345                         pad_hi = 0;
    346 
    347                 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);
    348                 memcpy((void *) (PA2KA(frame) + pad_lo),
    349                     (void *) (base + i * FRAME_SIZE + pad_lo),
    350                     FRAME_SIZE - pad_lo - pad_hi);
    351                 if (entry->p_flags & PF_X) {
    352                         smc_coherence_block((void *) (PA2KA(frame) + pad_lo),
    353                             FRAME_SIZE - pad_lo - pad_hi);
    354                 }
    355                 memsetb((void *) PA2KA(frame), pad_lo, 0);
    356                 memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,
    357                     0);
    358                 dirty = true;
    359         }
    360 
    361         if (dirty && area->sh_info) {
    362                 frame_reference_add(ADDR2PFN(frame));
    363                 btree_insert(&area->sh_info->pagemap, page - area->base,
    364                     (void *) frame, leaf);
    365         }
    366 
    367         if (area->sh_info)
    368                 mutex_unlock(&area->sh_info->lock);
    369 
    370         page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
    371         if (!used_space_insert(area, page, 1))
    372                 panic("Cannot insert used space.");
    373 
    374         return AS_PF_OK;
    375 }
    376 
    377 /** Free a frame that is backed by the ELF backend.
    378  *
    379  * The address space area and page tables must be already locked.
    380  *
    381  * @param area          Pointer to the address space area.
    382  * @param page          Page that is mapped to frame. Must be aligned to
    383  *                      PAGE_SIZE.
    384  * @param frame         Frame to be released.
    385  *
    386  */
    387 void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
    388 {
    389         elf_segment_header_t *entry = area->backend_data.segment;
    390         uintptr_t start_anon;
    391 
    392         ASSERT(page_table_locked(area->as));
    393         ASSERT(mutex_locked(&area->lock));
    394 
    395         ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE));
    396         ASSERT(page < entry->p_vaddr + entry->p_memsz);
    397 
    398         start_anon = entry->p_vaddr + entry->p_filesz;
    399 
    400         if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {
    401                 if (entry->p_flags & PF_W) {
    402                         /*
    403                          * Free the frame with the copy of writable segment
    404                          * data.
    405                          */
    406                         frame_free_noreserve(frame);
    407                 }
    408         } else {
    409                 /*
    410                  * The frame is either anonymous memory or the mixed case (i.e.
    411                  * lower part is backed by the ELF image and the upper is
    412                  * anonymous). In any case, a frame needs to be freed.
    413                  */
    414                 frame_free_noreserve(frame);
    415         }
    416 }
    417 
    418358/** @}
    419359 */
Note: See TracChangeset for help on using the changeset viewer.