From: Peter Dinda Date: Wed, 21 Aug 2013 20:17:23 +0000 (-0500) Subject: Updated userspace guest memory access tools for regions, plus added new fast function... X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=c5271d17ca93ad2ca9132a39212369c5f4feb2a9 Updated userspace guest memory access tools for regions, plus added new fast functionality for copies, hashes, and applies --- diff --git a/linux_usr/Makefile b/linux_usr/Makefile index 2d60e5a..0cf09ce 100644 --- a/linux_usr/Makefile +++ b/linux_usr/Makefile @@ -30,7 +30,8 @@ BASE_EXECS = v3_mem \ v3_debug \ v3_send \ v3_receive \ - v3_pci + v3_pci \ + v3_guest_mem_access # @@ -40,7 +41,6 @@ EXAMPLE_EXECS = v3_user_host_dev_example \ v3_os_debug \ v3_user_keyed_stream_example \ v3_user_keyed_stream_file \ - v3_guest_mem_example # # Currently experimental things @@ -170,7 +170,7 @@ libv3_guest_mem.a : v3_guest_mem.c v3_guest_mem.h v3_ctrl.h $(AR) ruv libv3_guest_mem.a v3_guest_mem.o rm -f v3_guest_mem.o -v3_guest_mem_example : v3_guest_mem_example.c libv3_guest_mem.a +v3_guest_mem_access : v3_guest_mem_access.c libv3_guest_mem.a $(CC) $(CFLAGS) $< -L. -lv3_guest_mem -o $@ diff --git a/linux_usr/v3_guest_mem.c b/linux_usr/v3_guest_mem.c index d23acc1..ed1cd44 100644 --- a/linux_usr/v3_guest_mem.c +++ b/linux_usr/v3_guest_mem.c @@ -7,66 +7,88 @@ #include "v3_guest_mem.h" -#warning FIX THE PARSER TO CONFORM TO NEW /proc/v3 VM output format - -#define GUEST_FILE "/proc/v3vee/v3-guests" -//#define GUEST_FILE "/441/pdinda/test.proc" +#define GUEST_FILE "/proc/v3vee/v3-guests-details" +//#define GUEST_FILE "/v-test/numa/palacios-devel/test.proc" #define MAXLINE 65536 struct v3_guest_mem_map * v3_guest_mem_get_map(char *vmdev) { FILE *f; + int rc; + int i; char buf[MAXLINE]; - char name[MAXLINE]; char dev[MAXLINE]; - char state[MAXLINE]; - uint64_t start, end; + uint64_t start, end, num; + uint64_t guest_cur; + uint64_t num_regions; if (!(f=fopen(GUEST_FILE,"r"))) { - fprintf(stderr,"Cannot open %s - is Palacios active?\n",GUEST_FILE); - return 0; - } - - // This is using the current "single memory region" model - // and will change when /proc convention changes to conform to - // multiple region model - while (fgets(buf,MAXLINE,f)) { - if (sscanf(buf, - "%s %s %s [0x%llx-0x%llx]", - name, - dev, - state, - &start, - &end)!=5) { - fprintf(stderr, "Cannot parse following line\n%s\n",buf); - fclose(f); + fprintf(stderr,"Cannot open %s - is Palacios active?\n",GUEST_FILE); return 0; - } - if (!strcmp(dev,vmdev)) { - struct v3_guest_mem_map *m = - (struct v3_guest_mem_map *) malloc(sizeof(struct v3_guest_mem_map)+1*sizeof(struct v3_guest_mem_block)); - if (!m) { - fprintf(stderr, "Cannot allocate space\n"); - fclose(f); - return 0; - } + } - memset(m,0,sizeof(struct v3_guest_mem_map)+1*sizeof(struct v3_guest_mem_block)); - - m->numblocks=1; - m->block[0].gpa=0; - m->block[0].hpa=(void*)start; - m->block[0].numpages = (end-start+1) / 4096; + while (1) { + if (!fgets(buf,MAXLINE,f)) { + fprintf(stderr,"Could not find info for %s\n",vmdev); + return 0; + } + if (sscanf(buf,"Device: %s",dev)==1) { + if (!strcmp(dev,vmdev)) { + // found our VM + break; + } + } + } + + // Now we need the number of regions + while (1) { + if (!fgets(buf,MAXLINE,f)) { + fprintf(stderr,"Could not find number of regions for %s\n",vmdev); + return 0; + } + if (sscanf(buf,"Regions: %llu",&num_regions)==1) { + break; + } + } + + struct v3_guest_mem_map *m = + (struct v3_guest_mem_map *) malloc(sizeof(struct v3_guest_mem_map)+num_regions*sizeof(struct v3_guest_mem_block)); + if (!m) { + fprintf(stderr, "Cannot allocate space\n"); fclose(f); - return m; - } + return 0; } - fprintf(stderr,"%s not found\n",vmdev); + memset(m,0,sizeof(struct v3_guest_mem_map)+num_regions*sizeof(struct v3_guest_mem_block)); + + m->numblocks=num_regions; + + // Now collect the region info + guest_cur=0; + while (iblock[i].gpa = (void*)guest_cur; + m->block[i].hpa = (void*)start; + m->block[i].numpages = (end-start) / 4096 + !!((end-start) % 4096); + if ((end-start)%4096) { + fprintf(stderr,"Odd, region %d is a non-integral number of pages"); + } + guest_cur+=end-start; + m->block[i].cumgpa=(void*)(guest_cur-1); + i++; + } + } + fclose(f); - return 0; + + return m; } @@ -88,8 +110,8 @@ int v3_map_guest_mem(struct v3_guest_mem_map *map) } for (i=0; inumblocks; i++) { - fprintf(stderr,"Mapping %llu bytes of /dev/mem offset 0x%llx\n", - map->block[i].numpages*4096, (off_t)(map->block[i].hpa)); + //fprintf(stderr,"Mapping %llu bytes of /dev/mem offset 0x%llx\n", + // map->block[i].numpages*4096, (off_t)(map->block[i].hpa)); map->block[i].uva = mmap(NULL, map->block[i].numpages*4096, PROT_READ | PROT_WRITE, @@ -125,3 +147,99 @@ int v3_unmap_guest_mem(struct v3_guest_mem_map *map) } return 0; } + + +void *v3_gpa_start(struct v3_guest_mem_map *map) +{ + return 0; // all guests start at zero for now +} + +void *v3_gpa_end(struct v3_guest_mem_map *map) +{ + struct v3_guest_mem_block *l = &(map->block[map->numblocks-1]); + + // currently, the regions are consecutive, so we just need the last block + return l->gpa+l->numpages*4096-1; +} + + +int v3_guest_mem_apply(void (*func)(void *data, uint64_t num_bytes, void *priv), + struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, void *priv) +{ + void *cur_gpa; + void *cur_uva; + uint64_t left_bytes; + uint64_t block_bytes; + + if (!(map->fd)) { + return -1; + } + + if (gpa < v3_gpa_start(map) || gpa+num_bytes-1 > v3_gpa_end(map)) { + return -1; + } + + cur_gpa = gpa; + left_bytes = num_bytes; + + while (left_bytes) { + cur_uva = v3_gpa_to_uva(map, cur_gpa, &block_bytes); + if (!cur_uva) { + return -1; + } + if (block_bytes>left_bytes) { + block_bytes = left_bytes; + } + func(cur_uva,block_bytes,priv); + left_bytes-=block_bytes; + cur_gpa+=block_bytes; + } + + return 0; +} + + + +static void copy_out(void *uva, uint64_t num_bytes, void *curoff) +{ + memcpy(*((void**)(curoff)), uva, num_bytes); + *(void**)curoff += num_bytes; +} + +static void copy_in(void *uva, uint64_t num_bytes, void *curoff) +{ + memcpy(uva, *((void**)(curoff)), num_bytes); + *(void**)curoff += num_bytes; +} + +static void do_hash(void *uva, uint64_t num_bytes, void *priv) +{ + uint64_t i; + uint64_t *curhash = (uint64_t *)priv; + + for (i=0;ifd) { + // not mapped + if (num_bytes) { *num_bytes=0;} + return 0; + } + + left = 0; right=map->numblocks-1; + + while (right>=left) { + middle = (right+left)/2; + if (gpa > map->block[middle].cumgpa) { + left=middle+1; + } else if (gpa < map->block[middle].gpa) { + right=middle-1; + } else { + break; + } + } + + if (right>=left) { + if (num_bytes) { + *num_bytes = map->block[middle].cumgpa - gpa + 1; + } + return map->block[middle].uva + (gpa - map->block[middle].gpa); + } else { + if (num_bytes) { + *num_bytes=0; + } + return 0; + } +} + +// efficiently map function over the specified guest memory +int v3_guest_mem_apply(void (*func)(void *data, uint64_t num_bytes, void *priv), + struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, void *priv); + +// read data out of guest +int v3_guest_mem_read(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, char *data); + +// write data into guest +int v3_guest_mem_write(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, char *data); + +// hash the guest's data +int v3_guest_mem_hash(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, uint64_t *hash); #endif diff --git a/linux_usr/v3_guest_mem_access.c b/linux_usr/v3_guest_mem_access.c new file mode 100644 index 0000000..2162ea8 --- /dev/null +++ b/linux_usr/v3_guest_mem_access.c @@ -0,0 +1,146 @@ +#include +#include + +#include "v3_guest_mem.h" + +void usage() +{ + fprintf(stderr,"usage: v3_guest_mem_access /dev/v3-vmN read|write|hash gpa_hex numbytes [numblocks; i++) { + // fprintf(stderr,"Region %llu: gpa=%p, hpa=%p, numpages=%llu\n", + // i, map->block[i].gpa, map->block[i].hpa, map->block[i].numpages); + //} + + if (v3_map_guest_mem(map)) { + fprintf(stderr, "Cannot map guest memory\n"); + free(map); + return -1; + } + + if (mode==READ || mode==WRITE) { + data = malloc(numbytes); + if (!data) { + fprintf(stderr, "Cannot allocate memory\n"); + v3_unmap_guest_mem(map); + return -1; + } + } + + switch (mode) { + case WRITE: + for (i=0;i -#include - -#include "v3_guest_mem.h" - -void usage() -{ - fprintf(stderr,"usage: v3_guest_mem_example /dev/v3-vmN read|write gpa_hex numbytes [numblocks; i++) { - fprintf(stderr,"Region %llu: gpa=%p, hpa=%p, numpages=%llu\n", - i, map->block[i].gpa, map->block[i].hpa, map->block[i].numpages); - } - - if (map->numblocks!=1) { - fprintf(stderr,"Don't handle multiregion map yet\n"); - return -1; - } - - if (!( ((void*)(gpa) >= map->block[0].gpa) && - (numbytes <= map->block[0].numpages*4096))) { - fprintf(stderr,"request (%p to %p) is out of range\n", - gpa, gpa+numbytes-1); - return -1; - } - - if (v3_map_guest_mem(map)) { - fprintf(stderr, "Cannot map guest memory\n"); - free(map); - return -1; - } - - for (i=0; iblock[0].uva+gpa+i))=cur; - } else { - cur = *((uint8_t *)(map->block[0].uva+gpa+i)); - // fprintf(stderr, "read %llu from uva=%p, ptr=%p\n",i,map->block[0].uva, map->block[0].uva+gpa+i); - if (write(1,&cur,1)!=1) { - fprintf(stderr,"can't write data to stdout for byte %llu\n", i); - break; - } - } - } - - - if (v3_unmap_guest_mem(map)) { - fprintf(stderr, "Cannot unmap guest memory\n"); - free(map); - return -1; - } -} -