usermode/library/mcore/src/segment.c

00001 /*
00002     Copyright (C) 2011 Computer Sciences Department, 
00003     University of Wisconsin -- Madison
00004 
00005     ----------------------------------------------------------------------
00006 
00007     This file is part of Mnemosyne: Lightweight Persistent Memory, 
00008     originally developed at the University of Wisconsin -- Madison.
00009 
00010     Mnemosyne was originally developed primarily by Haris Volos
00011     with contributions from Andres Jaan Tack.
00012 
00013     ----------------------------------------------------------------------
00014 
00015     Mnemosyne is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License
00017     as published by the Free Software Foundation, version 2
00018     of the License.
00019  
00020     Mnemosyne is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00028     Boston, MA  02110-1301, USA.
00029 
00030 ### END HEADER ###
00031 */
00032 
00033 /* System header files */
00034 #include <sys/stat.h>
00035 #include <sys/types.h>
00036 #include <sys/mman.h>
00037 #include <fcntl.h>
00038 #include <unistd.h>
00039 #include <string.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <sysexits.h>
00043 #include <assert.h>
00044 #include <dirent.h> 
00045 /* Mnemosyne common header files */
00046 #define _M_DEBUG_BUILD
00047 #include <debug.h>
00048 #include <result.h>
00049 /* Private local header files */
00050 #include "mcore_i.h"
00051 #include "files.h"
00052 #include "segment.h"
00053 #include "module.h"
00054 #include "hal/pcm_i.h"
00055 #include "pregionlayout.h"
00056 #include "config.h"
00057 
00058 
00062 #define SEGMENTS_DIR mcore_runtime_settings.segments_dir
00063 
00064 
00065 #define M_DEBUG_SEGMENT 1
00066 
00067 m_segtbl_t m_segtbl;
00068 
00069 
00070 /* Check whether there is a hole where we can allocate memory from. */
00071 #undef TRY_ALLOC_IN_HOLES
00072 
00073 
00074 static inline void *segment_map(void *addr, size_t size, int prot, int flags, int segment_fd);
00075 static m_result_t segidx_find_entry_using_index(m_segidx_t *segidx, uint32_t index, m_segidx_entry_t **entryp);
00076 
00077 
00089 static
00090 void
00091 verify_backing_stores(m_segtbl_t *segtbl)
00092 {
00093         int              n;
00094         DIR              *d;
00095     struct dirent    *dir;
00096         uint32_t         index;
00097         uint32_t         segment_id; 
00098         uint64_t         segment_module_id; /* This is valid for the .persistent backing stores */
00099         m_segidx_entry_t *ientry;
00100         char             complete_path[256];
00101 
00102         d = opendir(SEGMENTS_DIR);
00103         if (d) {
00104                 while ((dir = readdir(d)) != NULL) {
00105                         n = sscanf(dir->d_name, "%u.%lu\n", &segment_id, &segment_module_id);
00106                         if (n == 2) {
00107                                 index = segment_id;
00108                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "Verifying backing store: %u.%lu\n", segment_id, segment_module_id);
00109                                 /* Backing store has a valid entry in the segment table? */
00110                                 if (!(segtbl->entries[index].flags & SGTB_VALID_ENTRY)) {
00111                                         /* No valid entry; erase backing store */
00112                                         sprintf(complete_path, "%s/%s", SEGMENTS_DIR, dir->d_name);
00113                                         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "Remove backing store: %s\n", complete_path);
00114                                         unlink(complete_path);
00115                                 }       
00116                                 /* If this is .persistent backing store then update the index */
00117                                 if (segment_module_id != (uint64_t) (-1LLU)) {
00118                                         if (segidx_find_entry_using_index(segtbl->idx, index, &ientry)
00119                                                 != M_R_SUCCESS) 
00120                                         {
00121                                                 M_INTERNALERROR("Cannot find index entry for valid table entry.");
00122                                         }
00123                                         ientry->module_id = segment_module_id;
00124                                 }
00125                         }       
00126                 }
00127                 closedir(d);
00128         }
00129 }
00130 
00131 
00132 static
00133 int 
00134 create_backing_store(char *file, size_t size)
00135 {
00136         int      fd;
00137         ssize_t  roundup_size;
00138         char     buf[1]; 
00139         
00140         fd = open(file, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR);
00141         if (fd < 0) {
00142                 return fd;
00143         }
00144         /* TRICK: We could create an empty file by seeking to the end of the file 
00145          * and writing a single zero byte there. However this would cause a page 
00146          * fault at the last page of the file and bring the page into the OS page 
00147          * cache. This would prevent us from observing the virtual to 
00148          * physical persistent frame mapping later after the file is mmaped to a persistent
00149          * memory region. This is an artifact of our implementation of the persistent 
00150          * mapping subsystem in the kernel. To avoid this problem we round up the file
00151          * of the size to N * PAGE_SIZE, where N=NUM_PAGES(size), and write a single 
00152          * byte at location N*PAGE_SIZE+1. 
00153          *
00154          * Another way would be to bypass the file cache and use DIRECT I/O.
00155          */
00156         roundup_size = SIZEOF_PAGES(size);
00157         assert(lseek(fd, roundup_size, SEEK_SET) !=  (off_t) -1);
00158         write(fd, buf, 1);
00159         fsync(fd); /* make sure the file metadata is synced */
00160         /* FIXME: sync directory as well to reflect the new file entry. */
00161 
00162         return fd;
00163 }
00164 
00165 m_result_t
00166 m_check_backing_store(char *path, ssize_t size)
00167 {
00168         m_result_t  rv = M_R_FAILURE;
00169         struct stat stat_buf;
00170         ssize_t     roundup_size;
00171 
00172         if (stat(path, &stat_buf)==0) {
00173                 roundup_size = SIZEOF_PAGES(size);
00174                 if (stat_buf.st_size > roundup_size) {
00175                         rv = M_R_SUCCESS;
00176                 } else {
00177                         rv = M_R_FAILURE; 
00178                 }
00179         }
00180         return rv;
00181 }
00182 
00183 static 
00184 m_result_t
00185 segidx_insert_entry_ordered(m_segidx_t *segidx, m_segidx_entry_t *new_entry, int lock)
00186 {
00187         m_segidx_entry_t *ientry;
00188 
00189         if (lock) {
00190                 pthread_mutex_lock(&(segidx->mutex));
00191         }
00192         /* 
00193          * Find the right location of the entry so that the list is ordered
00194          * incrementally by start address. 
00195          */
00196         list_for_each_entry(ientry, &(segidx->mapped_entries.list), list) {
00197                 if (ientry->segtbl_entry->start > new_entry->segtbl_entry->start) {
00198                         list_add_tail(&(new_entry->list), &(ientry->list));
00199                         goto out;
00200                 }
00201         }
00202         list_add_tail(&(new_entry->list), &(segidx->mapped_entries.list));
00203 
00204 out:
00205         if (lock) {
00206                 pthread_mutex_unlock(&(segidx->mutex));
00207         }
00208         return M_R_SUCCESS;
00209 }
00210 
00211 
00212 m_result_t
00213 segidx_create(m_segtbl_t *_segtbl, m_segidx_t **_segidxp)
00214 {
00215         m_result_t       rv;
00216         m_segidx_t       *_segidx;
00217         m_segidx_entry_t *entries;
00218         m_segtbl_entry_t *segtbl_entry;
00219         int              i;
00220 
00221         if (!(_segidx = (m_segidx_t *) malloc(sizeof(m_segidx_t)))) {
00222                 rv = M_R_NOMEMORY;
00223                 goto out;
00224         }
00225         
00226         if (!(entries = (m_segidx_entry_t *) calloc(SEGMENT_TABLE_NUM_ENTRIES,
00227                                                     sizeof(m_segidx_entry_t))))
00228         {
00229                 rv = M_R_NOMEMORY;
00230                 goto err_calloc;
00231         }
00232         pthread_mutex_init(&(_segidx->mutex), NULL);
00233         _segidx->all_entries = entries;
00234         INIT_LIST_HEAD(&(_segidx->mapped_entries.list));
00235         INIT_LIST_HEAD(&(_segidx->free_entries.list));
00236         for (i=0; i < SEGMENT_TABLE_NUM_ENTRIES; i++) {
00237                 segtbl_entry = entries[i].segtbl_entry = &_segtbl->entries[i];
00238                 entries[i].index = i;
00239                 entries[i].module_id = (uint64_t) (-1ULL);
00240                 if (segtbl_entry->flags & SGTB_VALID_ENTRY) {
00241                         segidx_insert_entry_ordered(_segidx, &(entries[i]), 0);
00242                 } else {
00243                         list_add_tail(&(entries[i].list), &(_segidx->free_entries.list));
00244                 }
00245         }
00246         *_segidxp = _segidx;
00247         rv = M_R_SUCCESS;
00248         goto out;
00249 err_calloc:
00250         free(_segidx);
00251 out:
00252         return rv;
00253 }
00254 
00255 
00256 static
00257 m_result_t
00258 segidx_destroy(m_segidx_t *segidx)
00259 {
00260         M_INTERNALERROR("Unimplemented functionality: segidx_destroy\n");
00261         return M_R_SUCCESS;
00262 }       
00263 
00264 
00265 static
00266 m_result_t 
00267 segidx_alloc_entry(m_segidx_t *segidx, m_segidx_entry_t **entryp)
00268 {
00269         m_result_t       rv = M_R_FAILURE;
00270         m_segidx_entry_t *entry;
00271         struct list_head *free_head;
00272         
00273 
00274         pthread_mutex_lock(&(segidx->mutex));
00275         if ((free_head = segidx->free_entries.list.next)) {
00276                 entry = list_entry(free_head, m_segidx_entry_t, list);
00277                 list_del_init(&(entry->list));
00278         } else {
00279                 rv = M_R_NOMEMORY;
00280                 goto out;
00281         }
00282         *entryp = entry;
00283         rv = M_R_SUCCESS;
00284         goto out;
00285 
00286 out:
00287         pthread_mutex_unlock(&(segidx->mutex));
00288         return rv;
00289 }
00290 
00291 
00292 static
00293 m_result_t 
00294 segidx_free_entry(m_segidx_t *segidx, m_segidx_entry_t *entry)
00295 {
00296         m_result_t       rv = M_R_FAILURE;
00297 
00298         if (!entry) {
00299                 rv = M_R_INVALIDARG;
00300                 return rv;
00301         }       
00302 
00303         pthread_mutex_lock(&(segidx->mutex));
00304         list_del_init(&(entry->list));
00305         list_add(&(entry->list), &(segidx->free_entries.list));
00306         rv = M_R_SUCCESS;
00307         goto unlock;
00308 
00309 unlock:
00310         pthread_mutex_unlock(&(segidx->mutex));
00311         return rv;
00312 }
00313 
00314 
00315 /* Not thread safe */
00316 static
00317 m_result_t 
00318 segidx_find_entry_using_addr(m_segidx_t *segidx, void *addr, m_segidx_entry_t **entryp)
00319 {
00320         m_segidx_entry_t *ientry;
00321         m_segtbl_entry_t *tentry;
00322         uintptr_t        start;
00323         uint32_t         size;
00324 
00325         list_for_each_entry(ientry, &segidx->mapped_entries.list, list) {
00326                 tentry = ientry->segtbl_entry;
00327                 start = tentry->start;
00328                 size = tentry->size;
00329                 if ((uintptr_t) addr >= start && (uintptr_t) addr < start+size) {
00330                         *entryp = ientry;
00331                         return M_R_SUCCESS;
00332                 }
00333         }
00334         return M_R_FAILURE;
00335 }
00336 
00337 
00338 
00339 /* Not thread safe */
00340 static
00341 m_result_t 
00342 segidx_find_entry_using_index(m_segidx_t *segidx, uint32_t index, m_segidx_entry_t **entryp)
00343 {
00344         if (index >= SEGMENT_TABLE_NUM_ENTRIES) {
00345                 return M_R_INVALIDARG;
00346         }
00347         *entryp = &segidx->all_entries[index];
00348         return M_R_SUCCESS;
00349 }
00350 
00351 
00352 /* Not thread safe */
00353 static
00354 m_result_t 
00355 segidx_find_entry_using_module_id(m_segidx_t *segidx, uint64_t module_id, m_segidx_entry_t **entryp)
00356 {
00357         m_segidx_entry_t *ientry;
00358 
00359         list_for_each_entry(ientry, &segidx->mapped_entries.list, list) {
00360                 if (ientry->module_id == module_id) {
00361                         *entryp = ientry;
00362                         return M_R_SUCCESS;
00363                 }
00364         }
00365         return M_R_FAILURE;
00366 }
00367 
00368 static
00369 uintptr_t
00370 segidx_find_free_region(m_segidx_t *segidx, uintptr_t start_addr, size_t length)
00371 {
00372         struct list_head *tmp_list;
00373         m_segidx_entry_t *max_ientry;
00374 
00375         pthread_mutex_lock(&segidx->mutex); 
00376         if ((tmp_list = segidx->mapped_entries.list.prev) !=  &segidx->mapped_entries.list) {
00377                 max_ientry = list_entry(tmp_list, m_segidx_entry_t, list);
00378                 if (start_addr < (max_ientry->segtbl_entry->start +     max_ientry->segtbl_entry->size)) {
00379                         start_addr = 0x0;
00380 #ifdef TRY_ALLOC_IN_HOLES
00381                         /* Check whether there is a hole where we can allocate memory */
00382                         prev_end_addr = SEGMENT_MAP_START;
00383                         list_for_each_entry(ientry, &(segidx->mapped_entries.list), list) {
00384                                 if (ientry->segtbl_entry->start - prev_end_addr > length) {
00385                                         start_addr = prev_end_addr;
00386                                         break;
00387                                 }
00388                                 prev_end_addr = ientry->segtbl_entry->start + ientry->segtbl_entry->size;
00389                         }
00390 #endif                  
00391                         /* If not found a hole then start from the maximum allocated address so far */
00392                         if (!start_addr) {
00393                                 start_addr = max_ientry->segtbl_entry->start +  max_ientry->segtbl_entry->size;
00394                         }       
00395                 }
00396         }
00397         pthread_mutex_unlock(&segidx->mutex);
00398         return start_addr;
00399 }
00400 
00401 
00402 static inline
00403 m_result_t
00404 segment_table_map(m_segtbl_t *segtbl)
00405 {
00406         char              segtbl_path[256];
00407         int               segtbl_fd;
00408 
00409         sprintf(segtbl_path, "%s/segment_table", SEGMENTS_DIR);
00410         if (m_check_backing_store(segtbl_path, SEGMENT_TABLE_SIZE) != M_R_SUCCESS) {
00411                 mkdir_r(SEGMENTS_DIR, S_IRWXU);
00412                 segtbl_fd = create_backing_store(segtbl_path, SEGMENT_TABLE_SIZE);
00413         } else {
00414                 segtbl_fd = open(segtbl_path, O_RDWR);
00415         }
00416         segtbl->entries = segment_map((void *) SEGMENT_TABLE_START, 
00417                                       SEGMENT_TABLE_SIZE, 
00418                                       PROT_READ|PROT_WRITE,
00419                                       MAP_PERSISTENT | MAP_SHARED,
00420                                           segtbl_fd);
00421         if (segtbl->entries == MAP_FAILED) {
00422                 assert(0 && "Going crazy...couldn't map the segment table\n");
00423                 return M_R_FAILURE;
00424         }
00425         return M_R_SUCCESS;
00426 }
00427 
00428 
00437 static 
00438 m_result_t
00439 segment_table_incarnate()
00440 {
00441         m_result_t rv;
00442 
00443         if ((rv = segment_table_map(&m_segtbl)) != M_R_SUCCESS) {
00444                 return rv;
00445         }
00446         if ((rv = segidx_create(&m_segtbl, &(m_segtbl.idx))) != M_R_SUCCESS) {
00447 
00448         }
00449         verify_backing_stores(&m_segtbl);
00450 
00451         return M_R_SUCCESS;
00452 }
00453 
00454 
00455 static inline
00456 void
00457 segment_table_print(m_segtbl_t *segtbl)
00458 {
00459         m_segidx_entry_t *ientry;
00460         m_segtbl_entry_t *tentry;
00461         uintptr_t        start;
00462         uintptr_t        end;
00463 
00464         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "PERSISTENT SEGMENT TABLE\n");
00465         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "========================\n");
00466         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "%16s   %16s %17s %10s\n", "start", "end", "size", "flags");
00467         list_for_each_entry(ientry, &segtbl->idx->mapped_entries.list, list) {
00468                 tentry = ientry->segtbl_entry;
00469                 start = (uintptr_t) tentry->start;
00470                 end   = (uintptr_t) tentry->start + (uintptr_t) tentry->size;
00471                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "0x%016lx - 0x%016lx %16luK", start, end, (long unsigned int) tentry->size/1024);
00472                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, " %7c%c%c%c\n", ' ',
00473                               (tentry->flags & SGTB_VALID_ENTRY)? 'V': '-',
00474                               (tentry->flags & SGTB_VALID_DATA)? 'D': '-',
00475                               (tentry->flags & SGTB_TYPE_SECTION)? 'S': '-'
00476                                  );
00477         }
00478 }
00479 
00480 
00481 void 
00482 m_segment_table_print()
00483 {
00484         segment_table_print(&m_segtbl);
00485 }
00486 
00487 
00488 m_result_t
00489 m_segment_table_alloc_entry(m_segtbl_t *segtbl, m_segtbl_entry_t **entryp)
00490 {
00491         m_result_t       rv;
00492         m_segidx_entry_t *ientry;
00493 
00494         rv = segidx_alloc_entry(segtbl->idx, &ientry);
00495         if (rv != M_R_SUCCESS) {
00496                 goto out;
00497         }
00498         *entryp = ientry->segtbl_entry;
00499 
00500 out:
00501         return rv;
00502 }
00503         
00504 
00508 static inline
00509 void *
00510 segment_map(void *addr, size_t size, int prot, int flags, int segment_fd)
00511 {
00512         void      *segmentp;
00513         uintptr_t start;
00514         uintptr_t end;
00515 
00516 
00517         if (segment_fd < 0) {
00518                 return ((void *) -1);
00519         }
00520         segmentp = mmap(addr, size, prot, 
00521                         flags | MAP_PERSISTENT| MAP_SHARED, 
00522                             segment_fd,
00523                             0);
00524                                    
00525         if (segmentp == MAP_FAILED) {
00526                 return segmentp;
00527         }
00528         /* 
00529          * Ensure mapped segment falls into the address space region reserved 
00530          * for persistent segments.
00531          */
00532         start = (uintptr_t) segmentp;
00533         end = start + size;
00534         if (start < PSEGMENT_RESERVED_REGION_START || 
00535             start > PSEGMENT_RESERVED_REGION_END ||
00536             end > PSEGMENT_RESERVED_REGION_END) 
00537         {
00538                 /* FIXME: unmap the segment */
00539                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "   limits : %016lx - %016lx\n", PSEGMENT_RESERVED_REGION_START, PSEGMENT_RESERVED_REGION_END);
00540                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "asked for : %016lx - %016lx\n", (uintptr_t) addr, (uintptr_t) addr + size);
00541                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "      got : %016lx - %016lx\n", start, end);
00542                 M_INTERNALERROR("Persistent segment not in the reserved address space region.\n");
00543                 return MAP_FAILED;
00544         }
00545 
00546         /* we don't want page prefetching on the persistent segment */
00547         if (madvise(segmentp, size, MADV_RANDOM) < 0) {
00548                 return MAP_FAILED;
00549         }
00550         return segmentp;
00551 }
00552 
00553 
00557 static 
00558 void *
00559 segment_map2(void *addr, size_t size, int prot, int flags, char *segment_path)
00560 {
00561         int  segment_fd;
00562         void *segmentp;
00563 
00564         segment_fd = open(segment_path, O_RDWR);
00565         if (segment_fd < 0) {
00566                 return ((void *) -1);
00567         }
00568 
00569         segmentp = segment_map(addr, size, prot, flags, segment_fd);
00570                                    
00571         if (segmentp == MAP_FAILED) {
00572                 close (segment_fd);
00573                 return segmentp;
00574         }
00575         return segmentp;
00576 }
00577 
00578 
00584 void
00585 segment_reincarnate_segments(m_segtbl_t *segtbl)
00586 {
00587         m_segidx_entry_t *ientry;
00588         m_segtbl_entry_t *tentry;
00589         uintptr_t        start;
00590         uintptr_t        end;
00591         char             path[256];
00592         void             *map_addr;
00593 
00594         list_for_each_entry(ientry, &segtbl->idx->mapped_entries.list, list) {
00595                 tentry = ientry->segtbl_entry;
00596                 if (tentry->flags & SGTB_TYPE_PMAP) {
00597                         sprintf(path, "%s/%d.0", SEGMENTS_DIR, ientry->index);
00598                 } else if (tentry->flags & SGTB_TYPE_SECTION) {
00599                         sprintf(path, "%s/%d.%lu", SEGMENTS_DIR, ientry->index, (long unsigned int) ientry->module_id);
00600                 } else {
00601                         M_INTERNALERROR("Unknown persistent segment type.\n");
00602                 }
00603                 start = (uintptr_t) tentry->start;
00604                 end   = (uintptr_t) tentry->start + (uintptr_t) tentry->size;
00605                 /* 
00606                  * We pass MAP_FIXED to force the segment be mapped in its previous 
00607                  * address space region.
00608                  */
00609                 /* FIXME: protection flags should be stored in the segment table */
00610                 map_addr = segment_map2((void *) start, (size_t) tentry->size, 
00611                                                                 PROT_READ|PROT_WRITE,
00612                                                                 MAP_FIXED,
00613                                                                 path);
00614                 if (map_addr == MAP_FAILED) {
00615                         M_INTERNALERROR("Cannot reincarnate persistent segment.\n");
00616                 }
00617         }
00618 }
00619 
00620 
00621 static
00622 void *
00623 pmap_internal_abs(void *start, size_t length, int prot, int flags, 
00624                   m_segidx_entry_t **entryp, uint32_t segtbl_entry_flags, uint64_t module_id)
00625 {
00626         char             path[256];
00627         uintptr_t        start_addr = (uintptr_t) start;
00628         void             *map_addr;
00629         int              fd;
00630         void             *rv = MAP_FAILED;
00631         m_segidx_entry_t *new_ientry;
00632         m_segtbl_entry_t *tentry;
00633         uint32_t         flags_val;
00634         
00635 
00636         if ((segidx_alloc_entry(m_segtbl.idx, &new_ientry)) != M_R_SUCCESS) {
00637                 rv = MAP_FAILED;
00638                 goto out;
00639         }       
00640         sprintf(path, "%s/%d.%lu", SEGMENTS_DIR, new_ientry->index, module_id);
00641 
00642         /* 
00643          * Round-up the size of the segment to be an integer multiple of 4K pages.
00644          * This doesn't add any extra memory overhead because the kernel already 
00645          * round-ups and makes segment management simpler.
00646          */
00647         length = SIZEOF_PAGES(length);
00648 
00649         if ((fd = create_backing_store(path, length)) < 0) {
00650                 rv = MAP_FAILED;
00651                 goto err_create_backing_store;
00652         }
00653         
00654         /* 
00655          * Passing a start_addr that overlaps with a region will cause segment_map 
00656          * (which in turn calls mmap) to return an address that is not always the 
00657          * first address starting from start_addr to be found free. 
00658          * I don't understand why so I make sure that I pass an address that 
00659          * is guaranteed not to overlap with any other persistent segment.
00660          */
00661         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "start_addr = %p\n", (void *) start_addr);
00662 
00663         if ((flags & MAP_FIXED) != MAP_FIXED) {
00664                 start_addr = segidx_find_free_region(m_segtbl.idx, start_addr, length);
00665         }       
00666         map_addr = segment_map((void *)start_addr, length, prot, flags, fd);
00667         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "new_start_addr = %p\n", (void *) start_addr);
00668         M_DEBUG_PRINT(M_DEBUG_SEGMENT, "map_addr = %p\n", map_addr);
00669         if (map_addr == MAP_FAILED) {
00670                 rv = MAP_FAILED;
00671                 goto err_segment_map;
00672         }
00673 
00674         /* Now update the segment table with the necessary segment information. */
00675         tentry = new_ientry->segtbl_entry;
00676         tentry->start = map_addr; /* PCM STORE */ 
00677         tentry->size = length;  /* PCM STORE */
00678         PCM_WB_FENCE(NULL);
00679         PCM_WB_FLUSH(NULL, &(tentry->start));
00680         PCM_WB_FLUSH(NULL, &(tentry->size));
00681         flags_val = segtbl_entry_flags;
00682         tentry->flags = flags_val;  /* PCM STORE */
00683         PCM_WB_FENCE(NULL);
00684         PCM_WB_FLUSH(NULL, &(tentry->flags));
00685 
00686         /* Insert the entry into the ordered index */
00687         segidx_insert_entry_ordered(m_segtbl.idx, new_ientry, 1);
00688 
00689         *entryp = new_ientry;
00690         rv = map_addr;
00691         goto out;
00692 
00693 err_segment_map:
00694 err_create_backing_store:
00695         segidx_free_entry(m_segtbl.idx, new_ientry);
00696 out:
00697         return rv;
00698 }
00699 
00700 
00701 static
00702 void *
00703 pmap_internal(void *start, size_t length, int prot, int flags, 
00704               m_segidx_entry_t **entryp, uint32_t segtbl_entry_flags, uint64_t module_id)
00705 {
00706         uintptr_t        start_addr = SEGMENT_MAP_START + (uintptr_t) start;
00707 
00708         segment_table_print(&m_segtbl);
00709         return pmap_internal_abs((void *) start_addr, length, prot, flags, 
00710                                  entryp, segtbl_entry_flags, module_id);
00711 }
00712 
00713 
00714 
00719 static
00720 m_result_t 
00721 segment_create_sections(m_segtbl_t *segtbl)
00722 {
00723         void             *mapped_addr;
00724         size_t           length;
00725         uintptr_t        persistent_section_absolute_addr;
00726         uintptr_t        GOT_section_absolute_addr;
00727         m_result_t       rv;
00728         module_dsr_t     *module_dsr;
00729         m_segtbl_entry_t *tentry;
00730         m_segidx_entry_t *ientry;
00731         uint32_t         flags_val;
00732         Elf_Data         *elfdata;
00733 
00734         rv = m_module_create_module_dsr_list(&module_dsr_list);
00735 
00736         list_for_each_entry(module_dsr, &module_dsr_list, list) {
00737                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "module_path = %s\n", module_dsr->module_path);
00738                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "module_id   = %lu\n", module_dsr->module_inode);
00739 
00740                 /* 
00741                  * If there is no valid entry for the persistent section of this module 
00742                  * then create it and map the segment.
00743                  */
00744                 if (segidx_find_entry_using_module_id(segtbl->idx, module_dsr->module_inode, &ientry) 
00745                     != M_R_SUCCESS)
00746                 {
00747                         length = module_dsr->persistent_shdr.sh_size;
00748                         mapped_addr = pmap_internal(0, length, PROT_READ|PROT_WRITE, 0, &ientry, 
00749                                             SGTB_TYPE_SECTION | SGTB_VALID_ENTRY, module_dsr->module_inode);
00750                         if (mapped_addr == MAP_FAILED) {
00751                                 M_INTERNALERROR("Cannot map .persistent section's segment.\n");
00752                         }
00753                 } else {
00754                         mapped_addr = (void *) ientry->segtbl_entry->start;
00755                         length = ientry->segtbl_entry->size;
00756                 }
00757 
00758                 /* 
00759                  * Our linker script ensures that relocation for modules that have 
00760                  * a .persistent section will always happen at offset 0x400000.
00761                  */
00762 
00763                 persistent_section_absolute_addr = (uintptr_t) (module_dsr->persistent_shdr.sh_addr+module_dsr->module_start-0x400000);
00764                 GOT_section_absolute_addr = (uintptr_t) (module_dsr->GOT_shdr.sh_addr+module_dsr->module_start-0x400000);
00765 
00766                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "persistent_section.start         = %p\n", 
00767                               (void *) persistent_section_absolute_addr);
00768                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "persistent_section.end           = %p\n", 
00769                               (void *) (persistent_section_absolute_addr + 
00770                               module_dsr->persistent_shdr.sh_size));
00771                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "persistent_section.sh_size       = %d\n", 
00772                               (int) module_dsr->persistent_shdr.sh_size);
00773                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "persistent_section.sh_size_pages = %d\n", 
00774                               (int) SIZEOF_PAGES(module_dsr->persistent_shdr.sh_size));
00775                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "GOT_section.start                = %p\n", 
00776                               (void *) GOT_section_absolute_addr);
00777                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "GOT_section.end                  = %p\n", 
00778                               (void *) GOT_section_absolute_addr+module_dsr->GOT_shdr.sh_size);
00779                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "GOT_section.sh_size              = %d\n", 
00780                               (int) module_dsr->GOT_shdr.sh_size);
00781 
00782 
00783                 m_module_relocate_symbols(GOT_section_absolute_addr,
00784                                           GOT_section_absolute_addr + module_dsr->GOT_shdr.sh_size,
00785                                           persistent_section_absolute_addr, 
00786                                           persistent_section_absolute_addr + module_dsr->persistent_shdr.sh_size, 
00787                                           (uintptr_t) mapped_addr,
00788                                           (uintptr_t) mapped_addr+length
00789                                          );
00790 
00791                 /* If data not valid then load them using the data found in the .persistent section */
00792                 if (!(ientry->segtbl_entry->flags & SGTB_VALID_DATA))
00793                 {
00794                         elfdata = NULL;
00795                         while ((elfdata = elf_getdata(module_dsr->persistent_scn, elfdata)))
00796                         {
00797                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "data.d_size = %d\n", (int) elfdata->d_size);    
00798                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "data.d_buf = %p\n", elfdata->d_buf);    
00799                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "start_addr = %lx\n", (uintptr_t) mapped_addr);  
00800                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "end_addr = %lx\n", (uintptr_t) mapped_addr + length);   
00801                                 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "length     = %u\n", (unsigned int) length);     
00802                                 memcpy(mapped_addr, elfdata->d_buf, elfdata->d_size);
00803                         }
00804 
00805                         tentry = ientry->segtbl_entry;
00806                         flags_val = tentry->flags | SGTB_VALID_DATA;
00807                         tentry->flags = flags_val; /* PCM STORE */
00808                         PCM_WB_FENCE(NULL);
00809                         PCM_WB_FLUSH(NULL, &(tentry->flags));
00810                 }
00811 
00812         } /* end of list_for_each_entry */
00813 
00814         return M_R_SUCCESS;
00815 }
00816 
00817 
00818 
00823 m_result_t 
00824 m_segmentmgr_init()
00825 {
00826         char buf[256];
00827 
00828         /* Clear previous life segments? */
00829         if (mcore_runtime_settings.reset_segments) {
00830                 /* what if buffer overflow attack -- who cares, this is a prototype */
00831                 sprintf(buf, "rm -rf %s", SEGMENTS_DIR);
00832                 system(buf);
00833         }
00834 
00835         segment_table_incarnate();
00836         segment_reincarnate_segments(&m_segtbl);
00837         segment_create_sections(&m_segtbl);
00838 
00839         segment_table_print(&m_segtbl);
00840 
00841         return M_R_SUCCESS;
00842 }
00843 
00844 
00848 m_result_t 
00849 m_segmentmgr_fini()
00850 {
00851         /* Nothing really to do here. */
00852         return M_R_SUCCESS;
00853 }
00854 
00855 
00856 /* Not thread safe */
00857 m_result_t 
00858 m_segment_find_using_addr(void *addr, m_segidx_entry_t **entryp)
00859 {
00860         return segidx_find_entry_using_addr(m_segtbl.idx, addr, entryp);
00861 }
00862 
00863 
00864 
00870 void *
00871 m_pmap(void *start, size_t length, int prot, int flags)
00872 {
00873         m_segidx_entry_t *ientry;
00874         void             *rv;
00875         rv = pmap_internal(start, length, prot, flags, &ientry, 
00876                            SGTB_TYPE_PMAP | SGTB_VALID_ENTRY | SGTB_VALID_DATA, 0);
00877         return rv;
00878 }
00879 
00880 
00885 void *
00886 m_pmap2(void *start, size_t length, int prot, int flags)
00887 {
00888         m_segidx_entry_t *ientry;
00889         void             *rv;
00890 
00891         rv = pmap_internal_abs(start, length, prot, flags, &ientry, 
00892                                SGTB_TYPE_PMAP | SGTB_VALID_ENTRY | SGTB_VALID_DATA, 0);
00893         return rv;
00894 }
00895 
00896 
00897 
00898 int 
00899 m_punmap(void *start, size_t length)
00900 {
00901         M_INTERNALERROR("Unimplemented functionality: m_punmap\n");
00902         return 0;
00903 }

Generated on Sat Apr 23 11:43:36 2011 for Mnemosyne by  doxygen 1.4.7