From: Peter Dinda Date: Wed, 13 Mar 2013 15:51:29 +0000 (-0500) Subject: User space library and example tool for accessing guest physical memory from host... X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=ab570b923abf061acf9f495e5f4178e8c2af0fcc User space library and example tool for accessing guest physical memory from host user space --- diff --git a/linux_usr/Makefile b/linux_usr/Makefile index e314209..609a4a4 100644 --- a/linux_usr/Makefile +++ b/linux_usr/Makefile @@ -39,7 +39,8 @@ BASE_EXECS = v3_mem \ EXAMPLE_EXECS = v3_user_host_dev_example \ v3_os_debug \ v3_user_keyed_stream_example \ - v3_user_keyed_stream_file + v3_user_keyed_stream_file \ + v3_guest_mem_example # # Currently experimental things @@ -63,7 +64,7 @@ COPIED_EXECS = v3_x0vncserver v3_x0gui # # Libraries that we need to build # -LIBS = libv3_user_host_dev.a libv3_user_keyed_stream.a libv3_ctrl.a +LIBS = libv3_user_host_dev.a libv3_user_keyed_stream.a libv3_ctrl.a libv3_guest_mem.a BUILD_EXECS = $(BASE_EXECS) $(EXAMPLE_EXECS) $(EXPERIMENTAL_EXECS) BUILD_LIBS = $(LIBS) @@ -149,6 +150,17 @@ v3_user_keyed_stream_file : v3_user_keyed_stream_file.c libv3_user_keyed_stream. $(CC) $(CFLAGS) $< -I../linux_module -L. -lv3_user_keyed_stream -o $@ +# guest memory access by mmap and example +# +libv3_guest_mem.a : v3_guest_mem.c v3_guest_mem.h v3_ctrl.h + $(CC) $(CFLAGS) -c v3_guest_mem.c + $(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 + $(CC) $(CFLAGS) $< -L. -lv3_guest_mem -o $@ + + # # VNC support is compiled separately diff --git a/linux_usr/v3_guest_mem.c b/linux_usr/v3_guest_mem.c new file mode 100644 index 0000000..24877eb --- /dev/null +++ b/linux_usr/v3_guest_mem.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#include "v3_guest_mem.h" + + +#define GUEST_FILE "/proc/v3vee/v3-guests" +//#define GUEST_FILE "/441/pdinda/test.proc" +#define MAXLINE 65536 + +struct v3_guest_mem_map * v3_guest_mem_get_map(char *vmdev) +{ + FILE *f; + char buf[MAXLINE]; + char name[MAXLINE]; + char dev[MAXLINE]; + char state[MAXLINE]; + uint64_t start, end; + + + 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); + 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; + fclose(f); + return m; + } + } + + fprintf(stderr,"%s not found\n",vmdev); + fclose(f); + return 0; + +} + +int v3_map_guest_mem(struct v3_guest_mem_map *map) +{ + uint64_t i; + + if (map->fd) { + fprintf(stderr, "Memory appears to already be mapped\n"); + return -1; + } + + map->fd = open("/dev/mem", O_RDWR | O_SYNC); + + if (map->fd<0) { + fprintf(stderr, "Cannot open /dev/mem - are you root?\n"); + map->fd=0; + return -1; + } + + 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)); + map->block[i].uva = mmap(NULL, + map->block[i].numpages*4096, + PROT_READ | PROT_WRITE, + MAP_SHARED, + map->fd, + (off_t) (map->block[i].hpa)); + + if (map->block[i].uva == MAP_FAILED) { + fprintf(stderr, "Failed to map block %llu\n",i); + map->block[i].uva=0; + v3_unmap_guest_mem(map); + return -1; + } + } + + return 0; + +} + +int v3_unmap_guest_mem(struct v3_guest_mem_map *map) +{ + uint64_t i; + + for (i=0; inumblocks; i++) { + if (map->block[i].uva) { + munmap(map->block[i].uva, map->block[i].numpages*4096); + map->block[i].uva=0; + } + } + if (map->fd) { + close(map->fd); + map->fd=0; + } + return 0; +} diff --git a/linux_usr/v3_guest_mem.h b/linux_usr/v3_guest_mem.h new file mode 100644 index 0000000..907502c --- /dev/null +++ b/linux_usr/v3_guest_mem.h @@ -0,0 +1,33 @@ +#ifndef _V3_GUEST_MEM_ +#define _V3_GUEST_MEM_ + +#include +#include "v3_ctrl.h" + +struct v3_guest_mem_block { + void *gpa; // guest physical address is + void *hpa; // mapped to this host physical address + void *uva; // which is mapped here in this process + uint64_t numpages; // this many 4K pages +}; + +// Whole memory map of guest's physical memory +// that is backed by host physical memory (ie, everything we +// can read or write from the host user space) +struct v3_guest_mem_map { + int fd; // used by mmap + uint64_t numblocks; + struct v3_guest_mem_block block[0]; +}; + +// This function gets the basic memory map, but does not map it +struct v3_guest_mem_map * v3_guest_mem_get_map(char *vmdev); +// This function mmaps it into the guest address space +// and fills out the "myaddr" fields +int v3_map_guest_mem(struct v3_guest_mem_map *map); +// This function unmaps it - it assumes myaddrs are valid +int v3_unmap_guest_mem(struct v3_guest_mem_map *map); + + +#endif + diff --git a/linux_usr/v3_guest_mem_example.c b/linux_usr/v3_guest_mem_example.c new file mode 100644 index 0000000..4dd6235 --- /dev/null +++ b/linux_usr/v3_guest_mem_example.c @@ -0,0 +1,96 @@ +#include +#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; + } +} +