v3_debug \
v3_send \
v3_receive \
- v3_pci
+ v3_pci \
+ v3_guest_mem_access
#
v3_os_debug \
v3_user_keyed_stream_example \
v3_user_keyed_stream_file \
- v3_guest_mem_example
#
# Currently experimental things
$(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 $@
#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 (i<num_regions) {
+ if (!fgets(buf,MAXLINE,f)) {
+ fprintf(stderr,"Did not find all regions...\n");
+ free(m);
+ return 0;
+ }
+ if (sscanf(buf," region %d has HPAs %llx-%llx",&num,&start,&end)==3) {
+ m->block[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;
}
}
for (i=0; i<map->numblocks; 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,
}
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;i<num_bytes;i++) {
+ *curhash += ((uint8_t*)uva)[i];
+ }
+}
+
+int v3_guest_mem_read(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, char *data)
+{
+ void *cpy_ptr=data;
+
+ return v3_guest_mem_apply(copy_out,map,gpa,num_bytes,&cpy_ptr);
+}
+
+int v3_guest_mem_write(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, char *data)
+{
+ void *cpy_ptr=data;
+
+ return v3_guest_mem_apply(copy_in,map,gpa,num_bytes,&cpy_ptr);
+}
+
+int v3_guest_mem_hash(struct v3_guest_mem_map *map, void *gpa, uint64_t num_bytes, uint64_t *hash)
+{
+ *hash = 0;
+
+ return v3_guest_mem_apply(do_hash,map,gpa,num_bytes,hash);
+}
+
#include "v3_ctrl.h"
struct v3_guest_mem_block {
- void *gpa; // guest physical address is
+ void *gpa; // guest physical address this region starts at
+ void *cumgpa; // cumulative GPA in the VM including this block
void *hpa; // mapped to this host physical address
void *uva; // which is mapped here in this process
uint64_t numpages; // this many 4K pages
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);
+// What is the first GPA of this guest that contains memory ?
+void *v3_gpa_start(struct v3_guest_mem_map *map);
+// What is the last GPA of this guest that contains memory ?
+void *v3_gpa_end(struct v3_guest_mem_map *map);
+// map from a gpa to a uva, optionally giving the number of
+// subsequent bytes for which the mapping is continguous
+static inline void *v3_gpa_to_uva(struct v3_guest_mem_map *map, void *gpa, uint64_t *num_bytes)
+{
+ uint64_t left, right, middle;
+ if (!map->fd) {
+ // 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
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+
+#include "v3_guest_mem.h"
+
+void usage()
+{
+ fprintf(stderr,"usage: v3_guest_mem_access /dev/v3-vmN read|write|hash gpa_hex numbytes [<data]\n");
+}
+
+int main(int argc, char *argv[])
+{
+ char *vmdev;
+ enum {READ, WRITE, HASH} mode;
+ uint64_t gpa;
+ uint64_t numbytes;
+ struct v3_guest_mem_map *map;
+ uint64_t i;
+ int rc;
+ uint64_t hash;
+ uint8_t *data=0;
+
+ if (argc!=5) {
+ usage();
+ return -1;
+ }
+
+ vmdev=argv[1];
+
+ if (toupper(argv[2][0])=='R') {
+ mode=READ;
+ } else if (toupper(argv[2][0])=='W') {
+ mode=WRITE;
+ } else if (toupper(argv[2][0])=='H') {
+ mode=HASH;
+ } else {
+ fprintf(stderr,"Unknown mode %s\n", argv[2]);
+ return -1;
+ }
+
+ if (sscanf(argv[3],"%llx",&gpa)!=1) {
+ fprintf(stderr,"Don't understand address %s\n",argv[3]);
+ return -1;
+ }
+
+ numbytes=atol(argv[4]);
+
+ if (!(map=v3_guest_mem_get_map(vmdev))) {
+ fprintf(stderr,"Cannot get guest memory map for %s\n",vmdev);
+ return -1;
+ }
+
+ //for (i=0; i< map->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<numbytes;) {
+ rc = read(0,data+i,(numbytes-i));
+ if (rc<=0) {
+ fprintf(stderr, "Cannot read from stdin\n");
+ free(data);
+ v3_unmap_guest_mem(map);
+ return -1;
+ } else {
+ i+=rc;
+ }
+ }
+ if (v3_guest_mem_write(map,(void*)gpa,numbytes,data)) {
+ fprintf(stderr, "Failed to write all of guest memory\n");
+ free(data);
+ v3_unmap_guest_mem(map);
+ return -1;
+ }
+
+ fprintf(stderr, "Write complete (%llu bytes)\n", numbytes);
+
+ free(data);
+
+ break;
+
+ case READ:
+ if (v3_guest_mem_read(map,(void*)gpa,numbytes,data)) {
+ fprintf(stderr, "Failed to read all of guest memory\n");
+ free(data);
+ v3_unmap_guest_mem(map);
+ return -1;
+ }
+ for (i=0;i<numbytes;) {
+ rc = write(1,data+i,(numbytes-i));
+ if (rc<=0) {
+ fprintf(stderr, "Cannot write to stdout\n");
+ free(data);
+ v3_unmap_guest_mem(map);
+ return -1;
+ } else {
+ i+=rc;
+ }
+ }
+
+ fprintf(stderr, "Read complete (%llu bytes)\n", numbytes);
+
+ free(data);
+
+ break;
+
+ case HASH:
+ if (v3_guest_mem_hash(map,(void*)gpa,numbytes,&hash)) {
+ fprintf(stderr, "Failed to hash all of guest memory\n");
+ v3_unmap_guest_mem(map);
+ return -1;
+ }
+
+ fprintf(stderr, "Hash complete (%llu bytes), result is 0x%llx\n", numbytes, hash);
+
+ break;
+
+ }
+
+
+ if (v3_unmap_guest_mem(map)) {
+ fprintf(stderr, "Cannot unmap guest memory\n");
+ free(map);
+ return -1;
+ }
+
+ return 0;
+}
+
+++ /dev/null
-#include <stdint.h>
-#include <stdio.h>
-
-#include "v3_guest_mem.h"
-
-void usage()
-{
- fprintf(stderr,"usage: v3_guest_mem_example /dev/v3-vmN read|write gpa_hex numbytes [<data]\n");
-}
-
-int main(int argc, char *argv[])
-{
- char *vmdev;
- enum {READ, WRITE} mode;
- uint64_t gpa;
- uint64_t numbytes;
- struct v3_guest_mem_map *map;
- uint64_t i;
-
- if (argc!=5) {
- usage();
- return -1;
- }
-
- vmdev=argv[1];
-
- if (toupper(argv[2][0])=='R') {
- mode=READ;
- } else if (toupper(argv[2][0]=='W')) {
- mode=WRITE;
- } else {
- fprintf(stderr,"Unknown mode %s\n", argv[2]);
- return -1;
- }
-
- if (sscanf(argv[3],"%llx",&gpa)!=1) {
- fprintf(stderr,"Don't understand address %s\n",argv[3]);
- return -1;
- }
-
- numbytes=atol(argv[4]);
-
- if (!(map=v3_guest_mem_get_map(vmdev))) {
- fprintf(stderr,"Cannot get guest memory map for %s\n",vmdev);
- return -1;
- }
-
- for (i=0; i< map->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; i<numbytes; i++) {
- uint8_t cur;
- if (mode==WRITE) {
- if (read(0,&cur,1)!=1) {
- fprintf(stderr,"can't get data from stdin for byte %llu\n", i);
- break;
- }
- *((uint8_t*)(map->block[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;
- }
-}
-