backend_anon.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 
00039 #include <mm/as.h>
00040 #include <mm/page.h>
00041 #include <genarch/mm/page_pt.h>
00042 #include <genarch/mm/page_ht.h>
00043 #include <mm/frame.h>
00044 #include <mm/slab.h>
00045 #include <synch/mutex.h>
00046 #include <adt/list.h>
00047 #include <adt/btree.h>
00048 #include <errno.h>
00049 #include <arch/types.h>
00050 #include <typedefs.h>
00051 #include <align.h>
00052 #include <arch.h>
00053 
00054 static int anon_page_fault(as_area_t *area, __address addr, pf_access_t access);
00055 static void anon_frame_free(as_area_t *area, __address page, __address frame);
00056 static void anon_share(as_area_t *area);
00057 
00058 mem_backend_t anon_backend = {
00059         .page_fault = anon_page_fault,
00060         .frame_free = anon_frame_free,
00061         .share = anon_share
00062 };
00063 
00074 int anon_page_fault(as_area_t *area, __address addr, pf_access_t access)
00075 {
00076         __address frame;
00077 
00078         if (!as_area_check_access(area, access))
00079                 return AS_PF_FAULT;
00080 
00081         if (area->sh_info) {
00082                 btree_node_t *leaf;
00083                 
00084                 /*
00085                  * The area is shared, chances are that the mapping can be found
00086                  * in the pagemap of the address space area share info structure.
00087                  * In the case that the pagemap does not contain the respective
00088                  * mapping, a new frame is allocated and the mapping is created.
00089                  */
00090                 mutex_lock(&area->sh_info->lock);
00091                 frame = (__address) btree_search(&area->sh_info->pagemap,
00092                         ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
00093                 if (!frame) {
00094                         bool allocate = true;
00095                         int i;
00096                         
00097                         /*
00098                          * Zero can be returned as a valid frame address.
00099                          * Just a small workaround.
00100                          */
00101                         for (i = 0; i < leaf->keys; i++) {
00102                                 if (leaf->key[i] == ALIGN_DOWN(addr, PAGE_SIZE)) {
00103                                         allocate = false;
00104                                         break;
00105                                 }
00106                         }
00107                         if (allocate) {
00108                                 frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
00109                                 memsetb(PA2KA(frame), FRAME_SIZE, 0);
00110                                 
00111                                 /*
00112                                  * Insert the address of the newly allocated frame to the pagemap.
00113                                  */
00114                                 btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base, (void *) frame, leaf);
00115                         }
00116                 }
00117                 frame_reference_add(ADDR2PFN(frame));
00118                 mutex_unlock(&area->sh_info->lock);
00119         } else {
00120 
00121                 /*
00122                  * In general, there can be several reasons that
00123                  * can have caused this fault.
00124                  *
00125                  * - non-existent mapping: the area is an anonymous
00126                  *   area (e.g. heap or stack) and so far has not been
00127                  *   allocated a frame for the faulting page
00128                  *
00129                  * - non-present mapping: another possibility,
00130                  *   currently not implemented, would be frame
00131                  *   reuse; when this becomes a possibility,
00132                  *   do not forget to distinguish between
00133                  *   the different causes
00134                  */
00135                 frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0));
00136                 memsetb(PA2KA(frame), FRAME_SIZE, 0);
00137         }
00138         
00139         /*
00140          * Map 'page' to 'frame'.
00141          * Note that TLB shootdown is not attempted as only new information is being
00142          * inserted into page tables.
00143          */
00144         page_mapping_insert(AS, addr, frame, as_area_get_flags(area));
00145         if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1))
00146                 panic("Could not insert used space.\n");
00147                 
00148         return AS_PF_OK;
00149 }
00150 
00159 void anon_frame_free(as_area_t *area, __address page, __address frame)
00160 {
00161         frame_free(ADDR2PFN(frame));
00162 }
00163 
00173 void anon_share(as_area_t *area)
00174 {
00175         link_t *cur;
00176 
00177         /*
00178          * Copy used portions of the area to sh_info's page map.
00179          */
00180         mutex_lock(&area->sh_info->lock);
00181         for (cur = area->used_space.leaf_head.next; cur != &area->used_space.leaf_head; cur = cur->next) {
00182                 btree_node_t *node;
00183                 int i;
00184                 
00185                 node = list_get_instance(cur, btree_node_t, leaf_link);
00186                 for (i = 0; i < node->keys; i++) {
00187                         __address base = node->key[i];
00188                         count_t count = (count_t) node->value[i];
00189                         int j;
00190                         
00191                         for (j = 0; j < count; j++) {
00192                                 pte_t *pte;
00193                         
00194                                 page_table_lock(area->as, false);
00195                                 pte = page_mapping_find(area->as, base + j*PAGE_SIZE);
00196                                 ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte));
00197                                 btree_insert(&area->sh_info->pagemap, (base + j*PAGE_SIZE) - area->base,
00198                                         (void *) PTE_GET_FRAME(pte), NULL);
00199                                 page_table_unlock(area->as, false);
00200                                 frame_reference_add(ADDR2PFN(PTE_GET_FRAME(pte)));
00201                         }
00202                                 
00203                 }
00204         }
00205         mutex_unlock(&area->sh_info->lock);
00206 }
00207 

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