/* * map_file_segment() -- map a [range of a] registered file segment. */ static int map_file_segment(segment_t *segp) { glctx_t *gcp = &glctx; char *memp; size_t size; int fd; int flags = segp->seg_flags; if (!flags) flags = MAP_PRIVATE; /* default */ if ((fd = segp->seg_fd) == SEG_FD_NONE) { fprintf(stderr, "%s: file %s not open\n", gcp->program_name, segp->seg_path); return SEG_ERR; } size = file_size(fd); /* * page align offset/length; verify fit in file */ segp->seg_offset = round_down_to_pagesize(segp->seg_offset); if (segp->seg_offset > size) { fprintf(stderr, "%s: offset 0x%lx beyond end of file %s\n", gcp->program_name, segp->seg_offset, segp->seg_path); return SEG_ERR; } if (segp->seg_length == 0) segp->seg_length = round_up_to_pagesize(size) - segp->seg_offset; else segp->seg_length = round_up_to_pagesize(segp->seg_length); memp = (char *)mmap(0, segp->seg_length, segp->seg_prot, flags, fd, segp->seg_offset); if (memp == MAP_FAILED) { int err = errno; fprintf(stderr, "%s: mmap of %s failed - %s\n", __FUNCTION__, segp->seg_path, strerror(err)); return SEG_ERR; } vprint("%s: mmap()ed file seg %s at 0x%lx-0x%lx\n", gcp->program_name, segp->seg_name, memp, memp+segp->seg_length-1); segp->seg_start = memp; return SEG_OK; }
void *nacl_dyncode_alloc_fixed (void *dest, size_t code_size, size_t data_size, size_t data_offset) { /* TODO(eaeltsin): probably these alignment requirements are overly strict. If really so, support unaligned case. */ assert (dest == round_up_to_pagesize (dest)); assert (data_offset == round_up_to_pagesize (data_offset)); nacl_dyncode_alloc_init (); if (nacl_next_code > dest) { return NULL; } nacl_next_code = dest; code_size = round_up_to_pagesize (code_size); data_size = round_up_to_pagesize (data_size); if (data_size != 0) { size_t last_offset = nacl_next_data - nacl_next_code; if (data_offset > last_offset) { /* Leaves unused space in the data area. */ nacl_next_data += data_offset - last_offset; } else if (data_offset < last_offset) { /* Cannot move code. */ return NULL; } assert (nacl_next_code + data_offset == nacl_next_data); /* Check whether the data space is available and reserve it. MAP_FIXED cannot be used because it overwrites existing mappings. Instead, fail if returned value is different from address hint. */ void *mapped = __mmap (nacl_next_data, data_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mapped == MAP_FAILED) { return NULL; } if (mapped != nacl_next_data) { __munmap (nacl_next_data, data_size); return NULL; } } nacl_next_data += data_size; nacl_next_code += code_size; return dest; }
/* Allocate space for code and data simultaneously. This is a simple allocator that doesn't know how to deallocate. */ void *nacl_dyncode_alloc (size_t code_size, size_t data_size, size_t data_offset) { assert (data_offset == round_up_to_pagesize (data_offset)); nacl_dyncode_alloc_init (); code_size = round_up_to_pagesize (code_size); data_size = round_up_to_pagesize (data_size); if (data_size != 0) { size_t last_offset = nacl_next_data - nacl_next_code; if (data_offset > last_offset) { /* Leaves unused space in the data area. */ nacl_next_data += data_offset - last_offset; } else if (data_offset < last_offset) { /* Leaves unused space in the code area. */ nacl_next_code += last_offset - data_offset; } assert (nacl_next_code + data_offset == nacl_next_data); /* Check whether the data space is available and reserve it. MAP_FIXED cannot be used because it overwrites existing mappings. Instead, fail if returned value is different from address hint. TODO(mseaborn): Retry on failure or avoid failure by reserving a big chunk of address space at startup. */ void *mapped = __mmap (nacl_next_data, data_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mapped == MAP_FAILED) { return NULL; } if (mapped != nacl_next_data) { __munmap (nacl_next_data, data_size); return NULL; } } void *code_addr = nacl_next_code; nacl_next_data += data_size; nacl_next_code += code_size; return code_addr; }
/* * segment_mbind() - set memory policy for a range of specified segment * * NOTE: offset is relative to start of mapping, not start of file */ int segment_mbind(char *name, range_t * range, int policy, nodemask_t * nodemask, int flags) { glctx_t *gcp = &glctx; segment_t *segp; char *start; off_t offset; size_t length, maxlength; int ret; segp = segment_get(name); if (segp == NULL) { fprintf(stderr, "%s: no such segment: %s\n", gcp->program_name, name); return SEG_ERR; } if (segp->seg_start == MAP_FAILED) { fprintf(stderr, "%s: segment %s not mapped\n", gcp->program_name, name); return SEG_ERR; } offset = round_down_to_pagesize(range->offset); if (offset >= segp->seg_length) { fprintf(stderr, "%s: offset %ld is past end of segment %s\n", gcp->program_name, offset, name); return SEG_ERR; } start = segp->seg_start + offset; maxlength = segp->seg_length - offset; length = range->length; if (length) length = round_up_to_pagesize(length); /* * note: we silently truncate to max length [end of segment] */ if (length == 0 || length > maxlength) length = maxlength; ret = mbind(segp->seg_start + offset, length, policy, nodemask->n, NUMA_NUM_NODES, flags); if (ret == -1) { int err = errno; fprintf(stderr, "%s: mbind() of segment %s failed - %s\n", gcp->program_name, name, strerror(err)); return SEG_ERR; } return SEG_OK; }
/* * segment_register: register an anon, file or shm segment based on args. * for anon and shm, 'name' = segment name. * for file, 'name' = path name; segment name = basename(path) * * returns: !0 on success; 0 on failure */ int segment_register(seg_type_t type, char *name, range_t *range, int flags) { glctx_t *gcp = &glctx; segment_t *segp; char *path; segp = segment_get(basename(name)); /* ensure unique name */ if (segp != NULL) { fprintf(stderr, "%s: segment %s already exists\n", gcp->program_name, segp->seg_name); return SEG_ERR; } segp = get_seg_slot(); if (segp == NULL) return SEG_ERR; path = strdup(name); /* save a copy */ segp->seg_name = strdup(basename(name)); segp->seg_start = MAP_FAILED; segp->seg_length = round_up_to_pagesize(range->length); segp->seg_offset = round_down_to_pagesize(range->offset); segp->seg_type = type; segp->seg_flags = flags; /* possibly 0 */ segp->seg_prot = PROT_READ|PROT_WRITE; /* default */ segp->seg_fd = SEG_FD_NONE; segp->seg_shmid = SHM_ID_NONE; switch (type) { case SEGT_ANON: free(path); break; case SEGT_FILE: segp->seg_path = path; return open_file(segp); break; case SEGT_SHM: free(path); return get_shm_segment(segp); break; default: free(path); } return SEG_OK; }
static void nacl_dyncode_alloc_init (void) { extern char __etext[]; /* Defined by the linker script */ if (nacl_next_code) { return; } /* Place data after whatever brk() heap has been allocated so far. This will mean the brk() heap cannot be extended any further. TODO(mseaborn): Ideally place ld.so and brk() heap at a high address so that library data can be mapped below and not get in the way of the brk() heap. */ nacl_next_code = __etext; nacl_next_data = (char *) round_up_to_pagesize((size_t) __sbrk(0)); }
/* * segment_touch() - "touch" [read or write] each page of specified range * -- from offset to offset+length -- to fault in or to * test protection. * NOTE: offset is relative to start of mapping, not start of file! */ int segment_touch(char *name, range_t *range, int rw) { glctx_t *gcp = &glctx; segment_t *segp; off_t offset; size_t length, maxlength; unsigned long *memp; struct timeval t_start, t_end; segp = segment_get(name); if (segp == NULL) { fprintf(stderr, "%s: no such segment: %s\n", gcp->program_name, name); return SEG_ERR; } offset = round_down_to_pagesize(range->offset); if (offset >= segp->seg_length) { fprintf(stderr, "%s: offset %ld is past end of segment %s\n", gcp->program_name, offset, name); return SEG_ERR; } memp = (unsigned long*)(segp->seg_start + offset); maxlength = segp->seg_length - offset; length = range->length; if (length) length = round_up_to_pagesize(length); /* * note: we silently truncate to max length [end of segment] */ if (length == 0 || length > maxlength) length = maxlength; gettimeofday(&t_start, NULL); touch_memory(rw, memp, length); gettimeofday(&t_end, NULL); printf("%s: touched %d pages in %6.3f secs\n", gcp->program_name, length/gcp->pagesize, (float)(tv_diff_usec(&t_start, &t_end))/1000000.0); return SEG_OK; }
int segment_location(char *name, range_t * range) { glctx_t *gcp = &glctx; segment_t *segp; char *apage, *end; off_t offset; size_t length, maxlength; int pgid, i; bool need_nl; segp = segment_get(name); if (segp == NULL) { fprintf(stderr, "%s: no such segment: %s\n", gcp->program_name, name); return SEG_ERR; } if (segp->seg_start == MAP_FAILED) { fprintf(stderr, "%s: segment %s not mapped\n", gcp->program_name, name); return SEG_ERR; } offset = round_down_to_pagesize(range->offset); if (offset >= segp->seg_length) { fprintf(stderr, "%s: offset %ld is past end of segment %s\n", gcp->program_name, offset, name); return SEG_ERR; } apage = segp->seg_start + offset; maxlength = segp->seg_length - offset; length = range->length; if (length) length = round_up_to_pagesize(length); /* * note: we silently truncate to max length [end of segment] */ if (length == 0 || length > maxlength) length = maxlength; end = apage + length; pgid = offset / gcp->pagesize; show_one_segment(segp, false); /* show mapping, no header */ printf("page offset "); for (i = 0; i < PG_PER_LINE; ++i) printf(" +%02d", i); printf("\n"); if (pgid & PPL_MASK) { /* * start partial line */ int pgid2 = pgid & ~PPL_MASK; printf("%12x: ", pgid2); while (pgid2 < pgid) { printf(" "); ++pgid2; } need_nl = true; } else need_nl = false; for (; apage < end; apage += gcp->pagesize, ++pgid) { int node; node = get_node(apage); if (node < 0) { fprintf(stderr, "\n%s: " "failed to get node for segment %s, offset 0x%x\n", gcp->program_name, name, SEG_OFFSET(segp, apage)); return SEG_ERR; } if ((pgid & PPL_MASK) == 0) { if (need_nl) printf("\n"); printf("%12x: ", pgid); /* start a new line */ need_nl = true; } printf(" %3d", node); if (signalled(gcp)) { reset_signal(); break; } } printf("\n"); return SEG_OK; }