backend_elf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <elf.h>
00039 #include <debug.h>
00040 #include <arch/types.h>
00041 #include <typedefs.h>
00042 #include <mm/as.h>
00043 #include <mm/frame.h>
00044 #include <mm/slab.h>
00045 #include <mm/page.h>
00046 #include <genarch/mm/page_pt.h>
00047 #include <genarch/mm/page_ht.h>
00048 #include <align.h>
00049 #include <memstr.h>
00050 #include <macros.h>
00051 #include <arch.h>
00052 
00053 static int elf_page_fault(as_area_t *area, __address addr, pf_access_t access);
00054 static void elf_frame_free(as_area_t *area, __address page, __address frame);
00055 static void elf_share(as_area_t *area);
00056 
00057 mem_backend_t elf_backend = {
00058         .page_fault = elf_page_fault,
00059         .frame_free = elf_frame_free,
00060         .share = elf_share
00061 };
00062 
00073 int elf_page_fault(as_area_t *area, __address addr, pf_access_t access)
00074 {
00075         elf_header_t *elf = area->backend_data.elf;
00076         elf_segment_header_t *entry = area->backend_data.segment;
00077         btree_node_t *leaf;
00078         __address base, frame;
00079         index_t i;
00080 
00081         if (!as_area_check_access(area, access))
00082                 return AS_PF_FAULT;
00083 
00084         ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz));
00085         i = (addr - entry->p_vaddr) >> PAGE_WIDTH;
00086         base = (__address) (((void *) elf) + entry->p_offset);
00087         ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
00088 
00089         if (area->sh_info) {
00090                 bool found = false;
00091 
00092                 /*
00093                  * The address space area is shared.
00094                  */
00095                  
00096                 mutex_lock(&area->sh_info->lock);
00097                 frame = (__address) btree_search(&area->sh_info->pagemap,
00098                         ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
00099                 if (!frame) {
00100                         int i;
00101 
00102                         /*
00103                          * Workaround for valid NULL address.
00104                          */
00105 
00106                         for (i = 0; i < leaf->keys; i++) {
00107                                 if (leaf->key[i] == ALIGN_DOWN(addr, PAGE_SIZE)) {
00108                                         found = true;
00109                                         break;
00110                                 }
00111                         }
00112                 }
00113                 if (frame || found) {
00114                         frame_reference_add(ADDR2PFN(frame));
00115                         page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
00116                         if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
00117                                 panic("Could not insert used space.\n");
00118                         mutex_unlock(&area->sh_info->lock);
00119                         return AS_PF_OK;
00120                 }
00121         }
00122         
00123         /*
00124          * The area is either not shared or the pagemap does not contain the mapping.
00125          */
00126         
00127         if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) {
00128                 /*
00129                  * Initialized portion of the segment. The memory is backed
00130                  * directly by the content of the ELF image. Pages are
00131                  * only copied if the segment is writable so that there
00132                  * can be more instantions of the same memory ELF image
00133                  * used at a time. Note that this could be later done
00134                  * as COW.
00135                  */
00136                 if (entry->p_flags & PF_W) {
00137                         frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
00138                         memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE);
00139                         
00140                         if (area->sh_info) {
00141                                 frame_reference_add(ADDR2PFN(frame));
00142                                 btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
00143                                         (void *) frame, leaf);
00144                         }
00145 
00146                 } else {
00147                         frame = KA2PA(base + i*FRAME_SIZE);
00148                 }       
00149         } else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
00150                 /*
00151                  * This is the uninitialized portion of the segment.
00152                  * It is not physically present in the ELF image.
00153                  * To resolve the situation, a frame must be allocated
00154                  * and cleared.
00155                  */
00156                 frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
00157                 memsetb(PA2KA(frame), FRAME_SIZE, 0);
00158 
00159                 if (area->sh_info) {
00160                         frame_reference_add(ADDR2PFN(frame));
00161                         btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
00162                                 (void *) frame, leaf);
00163                 }
00164 
00165         } else {
00166                 size_t size;
00167                 /*
00168                  * The mixed case.
00169                  * The lower part is backed by the ELF image and
00170                  * the upper part is anonymous memory.
00171                  */
00172                 size = entry->p_filesz - (i<<PAGE_WIDTH);
00173                 frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
00174                 memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0);
00175                 memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size);
00176 
00177                 if (area->sh_info) {
00178                         frame_reference_add(ADDR2PFN(frame));
00179                         btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base,
00180                                 (void *) frame, leaf);
00181                 }
00182 
00183         }
00184         
00185         if (area->sh_info)
00186                 mutex_unlock(&area->sh_info->lock);
00187         
00188         page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
00189         if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
00190                 panic("Could not insert used space.\n");
00191 
00192         return AS_PF_OK;
00193 }
00194 
00204 void elf_frame_free(as_area_t *area, __address page, __address frame)
00205 {
00206         elf_header_t *elf = area->backend_data.elf;
00207         elf_segment_header_t *entry = area->backend_data.segment;
00208         __address base;
00209         index_t i;
00210         
00211         ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz));
00212         i = (page - entry->p_vaddr) >> PAGE_WIDTH;
00213         base = (__address) (((void *) elf) + entry->p_offset);
00214         ASSERT(ALIGN_UP(base, FRAME_SIZE) == base);
00215         
00216         if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) {
00217                 if (entry->p_flags & PF_W) {
00218                         /*
00219                          * Free the frame with the copy of writable segment data.
00220                          */
00221                         frame_free(ADDR2PFN(frame));
00222                 }
00223         } else {
00224                 /*
00225                  * The frame is either anonymous memory or the mixed case (i.e. lower
00226                  * part is backed by the ELF image and the upper is anonymous).
00227                  * In any case, a frame needs to be freed.
00228                  */
00229                 frame_free(ADDR2PFN(frame)); 
00230         }
00231 }
00232 
00243 void elf_share(as_area_t *area)
00244 {
00245         elf_segment_header_t *entry = area->backend_data.segment;
00246         link_t *cur;
00247         btree_node_t *leaf, *node;
00248         __address start_anon = entry->p_vaddr + entry->p_filesz;
00249 
00250         /*
00251          * Find the node in which to start linear search.
00252          */
00253         if (area->flags & AS_AREA_WRITE) {
00254                 node = list_get_instance(area->used_space.leaf_head.next, btree_node_t, leaf_link);
00255         } else {
00256                 (void) btree_search(&area->sh_info->pagemap, start_anon, &leaf);
00257                 node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap, leaf);
00258                 if (!node)
00259                         node = leaf;
00260         }
00261 
00262         /*
00263          * Copy used anonymous portions of the area to sh_info's page map.
00264          */
00265         mutex_lock(&area->sh_info->lock);
00266         for (cur = &node->leaf_link; cur != &area->used_space.leaf_head; cur = cur->next) {
00267                 int i;
00268                 
00269                 node = list_get_instance(cur, btree_node_t, leaf_link);
00270                 
00271                 for (i = 0; i < node->keys; i++) {
00272                         __address base = node->key[i];
00273                         count_t count = (count_t) node->value[i];
00274                         int j;
00275                         
00276                         /*
00277                          * Skip read-only areas of used space that are backed
00278                          * by the ELF image.
00279                          */
00280                         if (!(area->flags & AS_AREA_WRITE))
00281                                 if (base + count*PAGE_SIZE <= start_anon)
00282                                         continue;
00283                         
00284                         for (j = 0; j < count; j++) {
00285                                 pte_t *pte;
00286                         
00287                                 /*
00288                                  * Skip read-only pages that are backed by the ELF image.
00289                                  */
00290                                 if (!(area->flags & AS_AREA_WRITE))
00291                                         if (base + (j + 1)*PAGE_SIZE <= start_anon)
00292                                                 continue;
00293                                 
00294                                 page_table_lock(area->as, false);
00295                                 pte = page_mapping_find(area->as, base + j*PAGE_SIZE);
00296                                 ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte));
00297                                 btree_insert(&area->sh_info->pagemap, (base + j*PAGE_SIZE) - area->base,
00298                                         (void *) PTE_GET_FRAME(pte), NULL);
00299                                 page_table_unlock(area->as, false);
00300                                 frame_reference_add(ADDR2PFN(PTE_GET_FRAME(pte)));
00301                         }
00302                                 
00303                 }
00304         }
00305         mutex_unlock(&area->sh_info->lock);
00306 }
00307 

Generated on Sun Jun 18 17:28:03 2006 for HelenOS Kernel (ppc64) by  doxygen 1.4.6