Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 30c4005 in mainline for kernel/generic/src/mm/backend_elf.c


Ignore:
Timestamp:
2011-04-29T19:56:07Z (11 years ago)
Author:
Maurizio Lombardi <m.lombardi85@…>
Branches:
lfn, master
Children:
2874547
Parents:
6b40ea7 (diff), afdcc60e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline improvements

File:
1 edited

Legend:

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

    r6b40ea7 r30c4005  
    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};
    6671
    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  */
    79 int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)
    80 {
    81         elf_header_t *elf = area->backend_data.elf;
     72static size_t elf_nonanon_pages_get(as_area_t *area)
     73{
    8274        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;
     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;
    9394       
    94         if (addr < ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE))
    95                 return AS_PF_FAULT;
     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        }
    96115       
    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  */
    239 void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)
    240 {
    241         elf_segment_header_t *entry = area->backend_data.segment;
    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         }
     116        return true;
    268117}
    269118
     
    356205}
    357206
     207void 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 */
     227int 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 */
     387void 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
    358418/** @}
    359419 */
Note: See TracChangeset for help on using the changeset viewer.