Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Lei Xia [Fri, 6 May 2011 02:50:06 +0000 (21:50 -0500)]
Conflicts:

palacios/src/vnet/Makefile

47 files changed:
linux_module/Makefile
linux_module/palacios-dev.c
linux_module/palacios-graphics-console.c [new file with mode: 0644]
linux_module/palacios-graphics-console.h [new file with mode: 0644]
linux_module/palacios-hashtable.c [new file with mode: 0644]
linux_module/palacios-hashtable.h [new file with mode: 0644]
linux_module/palacios-host-dev-user.h [new file with mode: 0644]
linux_module/palacios-host-dev.c [new file with mode: 0644]
linux_module/palacios-host-dev.h [new file with mode: 0644]
linux_module/palacios-keyed-stream.c [new file with mode: 0644]
linux_module/palacios-keyed-stream.h [new file with mode: 0644]
linux_module/palacios-vm.c
linux_module/palacios.h
linux_usr/Makefile
linux_usr/v3_user_host_dev.c [new file with mode: 0644]
linux_usr/v3_user_host_dev.h [new file with mode: 0644]
linux_usr/v3_user_host_dev_example.c [new file with mode: 0644]
linux_usr/x0vncserver [new file with mode: 0755]
palacios/include/palacios/vm_guest.h
palacios/src/devices/apic.c
palacios/src/devices/vga.c
palacios/src/extensions/ext_inspector.c
palacios/src/extensions/ext_vtime.c
palacios/src/palacios/mmu/vmm_shdw_pg_cache_32.h
palacios/src/palacios/mmu/vmm_shdw_pg_kvm_32.h
palacios/src/palacios/mmu/vmm_shdw_pg_kvm_64.h
palacios/src/palacios/mmu/vmm_shdw_pg_swapbypass_32.h
palacios/src/palacios/mmu/vmm_shdw_pg_swapbypass_64.h
palacios/src/palacios/mmu/vmm_shdw_pg_tlb_32.h
palacios/src/palacios/mmu/vmm_shdw_pg_tlb_64.h
palacios/src/palacios/svm.c
palacios/src/palacios/vm_guest_mem.c
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_direct_paging_32.h
palacios/src/palacios/vmm_direct_paging_32pae.h
palacios/src/palacios/vmm_direct_paging_64.h
palacios/src/palacios/vmm_extensions.c
palacios/src/palacios/vmm_mem.c
palacios/src/palacios/vmm_mem_hook.c
palacios/src/palacios/vmm_symspy.c
palacios/src/palacios/vmm_telemetry.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmx.c
palacios/src/palacios/vmx_ept.c
palacios/src/vnet/Makefile
palacios/src/vnet/null.c [new file with mode: 0644]

index 8aa7855..a1a4349 100644 (file)
@@ -13,7 +13,8 @@ v3vee-objs :=         palacios.o \
                palacios-dev.o \
                palacios-vm.o \
                palacios-mm.o \
-               palacios-queue.o 
+               palacios-queue.o \
+               palacios-hashtable.o
 
 ifdef V3_CONFIG_CONSOLE
        v3vee-objs +=   palacios-console.o
@@ -44,6 +45,20 @@ ifdef V3_CONFIG_SOCKET
        v3vee-objs += palacios-socket.o
 endif
 
+ifdef V3_CONFIG_KEYED_STREAMS
+       v3vee-objs += palacios-keyed-stream.o
+endif
+
+ifdef V3_CONFIG_HOST_DEVICE
+       v3vee-objs += palacios-host-dev.o
+endif
+
+ifdef V3_CONFIG_GRAPHICS_CONSOLE
+       v3vee-objs += palacios-graphics-console.o
+endif
+
+
+
 v3vee-objs += ../libv3vee.a 
 
 
index 60f01ec..be62f33 100644 (file)
 #include "palacios-inspector.h"
 #endif
 
+#ifdef V3_CONFIG_KEYED_STREAMS
+#include "palacios-keyed-stream.h"
+#endif
+
+
 MODULE_LICENSE("GPL");
 
 int mod_allocs = 0;
@@ -135,10 +140,31 @@ static long v3_dev_ioctl(struct file * filp,
            INIT_LIST_HEAD(&(guest->streams));
            INIT_LIST_HEAD(&(guest->files));
            INIT_LIST_HEAD(&(guest->sockets));
+#ifdef V3_CONFIG_HOST_DEVICE
+           INIT_LIST_HEAD(&(guest->hostdev.devs));
+#endif
            init_completion(&(guest->start_done));
            init_completion(&(guest->thread_done));
 
-           kthread_run(start_palacios_vm, guest, guest->name);
+           { 
+               struct task_struct * launch_thread = NULL;
+               // At some point we're going to want to allow the user to specify a CPU mask
+               // But for now, well just launch from the local core, and rely on the global cpu mask
+
+               preempt_disable();
+               launch_thread = kthread_create(start_palacios_vm, guest, guest->name);
+               
+               if (IS_ERR(launch_thread)) {
+                   preempt_enable();
+                   printk("Palacios error creating launch thread for vm (%s)\n", guest->name);
+                   return -EFAULT;
+               }
+
+               kthread_bind(launch_thread, smp_processor_id());
+               preempt_enable();
+
+               wake_up_process(launch_thread);
+           }
 
            wait_for_completion(&(guest->start_done));
 
@@ -241,10 +267,18 @@ static int __init v3_init(void) {
     palacios_file_init();
 #endif
 
+#ifdef V3_CONFIG_KEYED_STREAMS
+    palacios_init_keyed_streams();
+#endif
+
 #ifdef V3_CONFIG_CONSOLE
     palacios_init_console();
 #endif
 
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
+    palacios_init_graphics_console();
+#endif
+
 #ifdef V3_CONFIG_EXT_INSPECTOR
     palacios_init_inspector();
 #endif
@@ -261,6 +295,10 @@ static int __init v3_init(void) {
     palacios_init_vnet();
 #endif
 
+#ifdef V3_CONFIG_HOST_DEVICE
+    palacios_init_host_dev();
+#endif
+
     return 0;
 
  failure1:
diff --git a/linux_module/palacios-graphics-console.c b/linux_module/palacios-graphics-console.c
new file mode 100644 (file)
index 0000000..0b03b62
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Palacios VM Graphics Console Interface (shared framebuffer between palacios and host)
+ * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
+ */
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+
+#include <interfaces/vmm_console.h>
+#include <palacios/vmm_host_events.h>
+
+#include "palacios.h"
+#include "palacios-graphics-console.h"
+
+
+/*
+
+  This is an implementation of the Palacios Graphics Console interface that
+  is designed to interact with a vnc server running in user space, 
+  typically something based on x0vncserver.  
+
+  The basic idea is that we manage a frame buffer that we share with
+  palacios.   Palacios draws whatever it likes on it.  
+  The user-land vncserver will send us requests   for fb updates, which
+  we implement by copying the FB to it.   When the user-land sends us characters, etc,
+  we deliver those immediately to palacios via the deliver_key and deliver_mouse
+  event interfaces.  The end-result is that whatever the graphics system
+  in palacios renders is visible via vnc.
+
+*/
+
+static v3_graphics_console_t g_open(void * priv_data, 
+                                   struct v3_frame_buffer_spec *desired_spec,
+                                   struct v3_frame_buffer_spec *actual_spec)
+{
+    struct v3_guest * guest = (struct v3_guest *)priv_data;
+    struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
+    uint32_t mem;
+
+    if(gc->data) { 
+       printk("palacios: framebuffer already allocated - returning it\n");
+       *actual_spec=gc->spec;
+       gc->cons_refcount++;
+       gc->data_refcount++;
+       return gc;
+    }
+
+    mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
+
+    printk("palacios: allocating %u bytes for %u by %u by %u buffer\n",
+          mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
+
+    gc->data = kmalloc(mem,GFP_KERNEL);
+
+    if (!(gc->data)) { 
+       printk("palacios: unable to allocate memory for frame buffer\n");
+       return 0;
+    }
+
+    gc->spec = *desired_spec;
+
+    *actual_spec = gc->spec;
+
+    gc->guest=guest;
+    
+    gc->cons_refcount++;
+    gc->data_refcount++;
+
+    printk("palacios: allocated frame buffer\n");
+
+    return gc;
+}
+
+static  void g_close(v3_graphics_console_t cons)
+{
+    struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
+
+    gc->cons_refcount--;
+    gc->data_refcount--;
+
+    if (gc->data_refcount<gc->cons_refcount) { 
+       printk("palacios: error!   data refcount is less than console refcount for graphics console\n");
+    }
+
+    if (gc->cons_refcount>0) { 
+       return;
+    } else {
+       if (gc->cons_refcount<0) { 
+           printk("palacios: error!  refcount for graphics console is negative on close!\n");
+       }
+       if (gc->data_refcount>0) { 
+           printk("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
+           return;
+       }
+       if (gc->data) { 
+           kfree(gc->data);
+           gc->data=0;
+       }
+    }
+}
+
+static void * g_get_data_read(v3_graphics_console_t cons, 
+                             struct v3_frame_buffer_spec *cur_spec)
+{
+    struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
+    
+    if (gc->data_refcount<=0) { 
+       printk("palacios: error!  data refcount is <= 0 in get_data_read\n");
+    }
+
+    gc->data_refcount++;
+    
+    *cur_spec=gc->spec;
+    
+    return gc->data;
+}
+
+static void g_release_data_read(v3_graphics_console_t cons)
+{
+    struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
+    
+    gc->data_refcount--;
+
+    if (gc->data_refcount<=0) { 
+       printk("palacios: error!  data refcount is <= zero in release_data_read\n");
+    }
+    
+}
+
+static void *g_get_data_rw(v3_graphics_console_t cons, 
+                          struct v3_frame_buffer_spec *cur_spec)
+{
+    return g_get_data_read(cons,cur_spec);
+}
+
+
+static void g_release_data_rw(v3_graphics_console_t cons)
+{
+    return g_release_data_read(cons);
+}
+
+
+static int g_changed(v3_graphics_console_t cons)
+{
+    struct palacios_graphics_console *gc = 
+       (struct palacios_graphics_console *) cons;
+
+#if 0
+    int rc =  !(gc->num_updates % 1000);
+    
+    gc->num_updates++;
+    
+    return rc;
+#else
+    return 1;
+#endif
+}
+
+
+
+static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
+{
+    struct v3_keyboard_event e;
+    e.status=0;
+    e.scan_code=scancode;
+
+    v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
+    
+    return 0;
+}
+
+static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
+{
+    struct v3_mouse_event e;
+    e.data[0]=x;
+    e.data[1]=y;
+    e.data[2]=buttons;   // These three are completely wrong, of course - ignoring mouse for now
+
+    v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
+
+    return 0;
+}
+
+static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
+{
+    .open  = g_open,
+    .close = g_close,
+
+    .get_data_read = g_get_data_read,
+    .release_data_read = g_release_data_read,
+    .get_data_rw = g_get_data_rw,
+    .release_data_rw = g_release_data_rw,
+
+    .changed = g_changed,
+};
+
+
+int palacios_init_graphics_console( void ) {
+
+    V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
+    
+    return 0;
+}
+
+
+int palacios_graphics_console_user_query(struct palacios_graphics_console *cons, 
+                                        struct v3_fb_query_response __user *u)
+{
+    struct v3_fb_query_response q;
+    
+    
+    if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) { 
+       printk("palacios: copy from user in getting query in fb\n");
+       return -EFAULT;
+    }
+    
+    switch (q.request_type) { 
+       case V3_FB_SPEC:
+           // returns only the spec for the FB
+           q.spec = cons->spec;
+
+           break;
+
+       case V3_FB_UPDATE: 
+           // returns whether an update is available for the region
+           // currently always true
+           q.updated = 1;
+
+           break;
+
+       case V3_FB_DATA_BOX: {
+           // Not curently implemented
+           printk("palacios: request for data in bounding box unsupported currently\n");
+           return -EFAULT;
+
+       }
+
+           break;
+           
+       case V3_FB_DATA_ALL: {
+           // First let's sanity check to see if they are requesting the same
+           // spec that we have
+           if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { 
+               printk("palacios: request for data with non-matching fb spec \n");
+               return -EFAULT;
+           }
+           // Now let's indicate an update is in the pointer and copy across the data
+           if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { 
+               printk("palacios: unable to copy fb content to user\n");
+               return -EFAULT;
+           }
+           q.updated=1;
+       }
+           break;
+           
+       default:
+           return -EFAULT;
+    }
+
+    // now we'll copy back any changes we made to the query/response structure
+    if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) { 
+       printk("palacios: unable to copy fb response to user\n");
+       return -EFAULT;
+    }
+
+    return 0;
+
+}
+
+int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
+                                        struct v3_fb_input __user  *u)
+{
+    struct v3_fb_input inp;
+    int rc=0;
+
+
+    if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) { 
+       printk("palacios: copy from user in getting input in fb\n");
+       return -EFAULT;
+    }
+       
+    if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) { 
+       rc = palacios_graphics_console_key(cons,inp.scan_code);
+    }
+
+    if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) { 
+       rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);
+    }
+
+    if (rc) { 
+       return -EFAULT;
+    } else {
+       return 0;
+    }
+}
diff --git a/linux_module/palacios-graphics-console.h b/linux_module/palacios-graphics-console.h
new file mode 100644 (file)
index 0000000..417a26b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Palacios VM Graphics Console Interface (shared framebuffer between palacios and host)
+ * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
+ */
+
+#ifndef __PALACIOS_GRAPHICS_CONSOLE_H__
+#define __PALACIOS_GRAPHICS_CONSOLE_H__
+
+#include <interfaces/vmm_graphics_console.h>
+
+struct palacios_graphics_console {
+    // descriptor for the data in the shared frame buffer
+    struct v3_frame_buffer_spec spec;
+    // the actual shared frame buffer
+    // Note that "shared" here means shared between palacios and us
+    // This data could of course also be shared with userland
+    void *data;
+
+    struct v3_guest * guest;
+
+    int cons_refcount;
+    int data_refcount;
+
+    uint32_t num_updates;
+
+    // Currently keystrokes and mouse movements are ignored
+
+    // currently, we will not worry about locking this
+    // lock_t ...
+};
+
+
+// This is the data structure that is passed back and forth with user-land
+// ioctl
+struct v3_fb_query_response {
+    enum { V3_FB_DATA_ALL, V3_FB_DATA_BOX, V3_FB_UPDATE, V3_FB_SPEC } request_type;
+    struct v3_frame_buffer_spec spec;    // in: desired spec; out: actual spec
+    uint32_t x, y, w, h;                 // region to copy (0s = all) in/out args
+    int updated;                         // whether this region has been updated or not
+    void __user *data;                   // user space pointer to copy data to
+};
+
+// This is what userland sends down for input events
+struct v3_fb_input {
+    enum { V3_FB_KEY, V3_FB_MOUSE, V3_FB_BOTH}             data_type;
+    uint8_t                              scan_code;
+    uint8_t                              mouse_data[3];
+};
+
+
+int palacios_init_graphics_console(void);
+
+int palacios_graphics_console_user_query(struct palacios_graphics_console *cons, 
+                                        struct v3_fb_query_response __user *fb);
+
+int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
+                                        struct v3_fb_input __user  *in);
+
+
+#endif
diff --git a/linux_module/palacios-hashtable.c b/linux_module/palacios-hashtable.c
new file mode 100644 (file)
index 0000000..6c025fc
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Palacios Hash Table 
+ * (c) Lei Xia, 2011
+ */
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include "palacios-hashtable.h"
+
+
+struct hash_entry {
+    addr_t key;
+    addr_t value;
+    uint_t hash;
+    struct hash_entry * next;
+};
+
+struct hashtable {
+    uint_t table_length;
+    struct hash_entry ** table;
+    uint_t entry_count;
+    uint_t load_limit;
+    uint_t prime_index;
+    uint_t (*hash_fn) (addr_t key);
+    int (*eq_fn) (addr_t key1, addr_t key2);
+};
+
+
+/* HASH FUNCTIONS */
+
+static inline uint_t do_hash(struct hashtable * htable, addr_t key) {
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    uint_t i = htable->hash_fn(key);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+
+    return i;
+}
+
+
+/* HASH AN UNSIGNED LONG */
+/* LINUX UNSIGHED LONG HASH FUNCTION */
+#ifdef __32BIT__
+/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
+#define GOLDEN_RATIO_PRIME 0x9e370001UL
+//#define BITS_PER_LONG 32
+#elif  defined(__64BIT__)
+/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
+#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
+//#define BITS_PER_LONG 64
+#else
+#error Define GOLDEN_RATIO_PRIME for your wordsize.
+#endif
+
+ulong_t palacios_hash_long(ulong_t val, uint_t bits) {
+    ulong_t hash = val;
+
+#ifdef __PALACIOS_64BIT__
+    /*  Sigh, gcc can't optimise this alone like it does for 32 bits. */
+    ulong_t n = hash;
+    n <<= 18;
+    hash -= n;
+    n <<= 33;
+    hash -= n;
+    n <<= 3;
+    hash += n;
+    n <<= 3;
+    hash -= n;
+    n <<= 4;
+    hash += n;
+    n <<= 2;
+    hash += n;
+#else
+    /* On some cpus multiply is faster, on others gcc will do shifts */
+    hash *= GOLDEN_RATIO_PRIME;
+#endif
+
+    /* High bits are more random, so use them. */
+    return hash >> (BITS_PER_LONG - bits);
+}
+
+/* HASH GENERIC MEMORY BUFFER */
+/* ELF HEADER HASH FUNCTION */
+ulong_t palacios_hash_buffer(uchar_t * msg, uint_t length) {
+    ulong_t hash = 0;
+    ulong_t temp = 0;
+    uint_t i;
+
+    for (i = 0; i < length; i++) {
+       hash = (hash << 4) + *(msg + i) + i;
+       if ((temp = (hash & 0xF0000000))) {
+           hash ^= (temp >> 24);
+       }
+       hash &= ~temp;
+    }
+    return hash;
+}
+
+/* indexFor */
+static inline uint_t indexFor(uint_t table_length, uint_t hash_value) {
+    return (hash_value % table_length);
+};
+
+#define freekey(X) kfree(X)
+
+
+static void * tmp_realloc(void * old_ptr, uint_t old_size, uint_t new_size) {
+    void * new_buf = kmalloc(new_size, GFP_KERNEL);
+
+    if (new_buf == NULL) {
+       return NULL;
+    }
+
+    memcpy(new_buf, old_ptr, old_size);
+    kfree(old_ptr);
+
+    return new_buf;
+}
+
+
+/*
+  Credit for primes table: Aaron Krowne
+  http://br.endernet.org/~akrowne/
+  http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
+*/
+static const uint_t primes[] = { 
+    53, 97, 193, 389,
+    769, 1543, 3079, 6151,
+    12289, 24593, 49157, 98317,
+    196613, 393241, 786433, 1572869,
+    3145739, 6291469, 12582917, 25165843,
+    50331653, 100663319, 201326611, 402653189,
+    805306457, 1610612741 };
+
+
+// this assumes that the max load factor is .65
+static const uint_t load_factors[] = {
+    35, 64, 126, 253,
+    500, 1003, 2002, 3999,
+    7988, 15986, 31953, 63907,
+    127799, 255607, 511182, 1022365,
+    2044731, 4089455, 8178897, 16357798,
+    32715575, 65431158, 130862298, 261724573,
+    523449198, 1046898282 };
+
+const uint_t prime_table_len = sizeof(primes) / sizeof(primes[0]);
+
+struct hashtable * palacios_create_htable(uint_t min_size,
+                                   uint_t (*hash_fn) (addr_t),
+                                   int (*eq_fn) (addr_t, addr_t)) {
+    struct hashtable * htable;
+    uint_t prime_index;
+    uint_t size = primes[0];
+
+    /* Check requested hashtable isn't too large */
+    if (min_size > (1u << 30)) {
+       return NULL;
+    }
+
+    /* Enforce size as prime */
+    for (prime_index = 0; prime_index < prime_table_len; prime_index++) {
+        if (primes[prime_index] > min_size) { 
+           size = primes[prime_index]; 
+           break; 
+       }
+    }
+
+    htable = (struct hashtable *)kmalloc(sizeof(struct hashtable), GFP_KERNEL);
+
+    if (htable == NULL) {
+       return NULL; /*oom*/
+    }
+
+    htable->table = (struct hash_entry **)kmalloc(sizeof(struct hash_entry*) * size, GFP_KERNEL);
+
+    if (htable->table == NULL) { 
+       kfree(htable); 
+       return NULL;  /*oom*/
+    }
+
+    memset(htable->table, 0, size * sizeof(struct hash_entry *));
+
+    htable->table_length  = size;
+    htable->prime_index   = prime_index;
+    htable->entry_count   = 0;
+    htable->hash_fn       = hash_fn;
+    htable->eq_fn         = eq_fn;
+    htable->load_limit    = load_factors[prime_index];
+
+    return htable;
+}
+
+
+static int hashtable_expand(struct hashtable * htable) {
+    /* Double the size of the table to accomodate more entries */
+    struct hash_entry ** new_table;
+    struct hash_entry * tmp_entry;
+    struct hash_entry ** entry_ptr;
+    uint_t new_size;
+    uint_t i;
+    uint_t index;
+
+    /* Check we're not hitting max capacity */
+    if (htable->prime_index == (prime_table_len - 1)) {
+       return 0;
+    }
+
+    new_size = primes[++(htable->prime_index)];
+
+    new_table = (struct hash_entry **)kmalloc(sizeof(struct hash_entry*) * new_size, GFP_KERNEL);
+
+    if (new_table != NULL) {
+        memset(new_table, 0, new_size * sizeof(struct hash_entry *));
+        /* This algorithm is not 'stable'. ie. it reverses the list
+         * when it transfers entries between the tables */
+
+        for (i = 0; i < htable->table_length; i++) {
+
+           while ((tmp_entry = htable->table[i]) != NULL) {
+               htable->table[i] = tmp_entry->next;
+          
+               index = indexFor(new_size, tmp_entry->hash);
+           
+               tmp_entry->next = new_table[index];
+           
+               new_table[index] = tmp_entry;
+           }
+        }
+
+        kfree(htable->table);
+
+        htable->table = new_table;
+    } else {
+       /* Plan B: realloc instead */
+
+       //new_table = (struct hash_entry **)realloc(htable->table, new_size * sizeof(struct hash_entry *));
+       new_table = (struct hash_entry **)tmp_realloc(htable->table, primes[htable->prime_index - 1], 
+                                                     new_size * sizeof(struct hash_entry *));
+
+       if (new_table == NULL) {
+           (htable->prime_index)--;
+           return 0;
+       }
+
+       htable->table = new_table;
+
+       memset(new_table[htable->table_length], 0, new_size - htable->table_length);
+
+       for (i = 0; i < htable->table_length; i++) {
+
+           for (entry_ptr = &(new_table[i]), tmp_entry = *entry_ptr; 
+                tmp_entry != NULL; 
+                tmp_entry = *entry_ptr) {
+
+               index = indexFor(new_size, tmp_entry->hash);
+
+               if (i == index) {
+                   entry_ptr = &(tmp_entry->next);
+               } else {
+                   *entry_ptr = tmp_entry->next;
+                   tmp_entry->next = new_table[index];
+                   new_table[index] = tmp_entry;
+               }
+           }
+       }
+    }
+
+    htable->table_length = new_size;
+
+    htable->load_limit   = load_factors[htable->prime_index];
+
+    return -1;
+}
+
+uint_t palacios_htable_count(struct hashtable * htable) {
+    return htable->entry_count;
+}
+
+int palacios_htable_insert(struct hashtable * htable, addr_t key, addr_t value) {
+    /* This method allows duplicate keys - but they shouldn't be used */
+    uint_t index;
+    struct hash_entry * new_entry;
+
+    if (++(htable->entry_count) > htable->load_limit) {
+       /* Ignore the return value. If expand fails, we should
+        * still try cramming just this value into the existing table
+        * -- we may not have memory for a larger table, but one more
+        * element may be ok. Next time we insert, we'll try expanding again.*/
+       hashtable_expand(htable);
+    }
+
+    new_entry = (struct hash_entry *)kmalloc(sizeof(struct hash_entry), GFP_KERNEL);
+
+    if (new_entry == NULL) { 
+       (htable->entry_count)--; 
+       return 0; /*oom*/
+    }
+
+    new_entry->hash = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, new_entry->hash);
+
+    new_entry->key = key;
+    new_entry->value = value;
+
+    new_entry->next = htable->table[index];
+
+    htable->table[index] = new_entry;
+
+    return -1;
+}
+
+
+int palacios_htable_change(struct hashtable * htable, addr_t key, addr_t value, int free_value) {
+    struct hash_entry * tmp_entry;
+    uint_t hash_value;
+    uint_t index;
+
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    tmp_entry = htable->table[index];
+
+    while (tmp_entry != NULL) {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
+
+           if (free_value) {
+               kfree((void *)(tmp_entry->value));
+           }
+
+           tmp_entry->value = value;
+           return -1;
+        }
+        tmp_entry = tmp_entry->next;
+    }
+    return 0;
+}
+
+
+
+int palacios_htable_inc(struct hashtable * htable, addr_t key, addr_t value) {
+    struct hash_entry * tmp_entry;
+    uint_t hash_value;
+    uint_t index;
+
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    tmp_entry = htable->table[index];
+
+    while (tmp_entry != NULL) {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
+
+           tmp_entry->value += value;
+           return -1;
+        }
+        tmp_entry = tmp_entry->next;
+    }
+    return 0;
+}
+
+
+int palacios_htable_dec(struct hashtable * htable, addr_t key, addr_t value) {
+    struct hash_entry * tmp_entry;
+    uint_t hash_value;
+    uint_t index;
+
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    tmp_entry = htable->table[index];
+
+    while (tmp_entry != NULL) {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hash_value == tmp_entry->hash) && (htable->eq_fn(key, tmp_entry->key))) {
+
+           tmp_entry->value -= value;
+           return -1;
+        }
+        tmp_entry = tmp_entry->next;
+    }
+    return 0;
+}
+
+
+/* returns value associated with key */
+addr_t palacios_htable_search(struct hashtable * htable, addr_t key) {
+    struct hash_entry * cursor;
+    uint_t hash_value;
+    uint_t index;
+  
+    hash_value = do_hash(htable, key);
+  
+    index = indexFor(htable->table_length, hash_value);
+  
+    cursor = htable->table[index];
+  
+    while (cursor != NULL) {
+       /* Check hash value to short circuit heavier comparison */
+       if ((hash_value == cursor->hash) && 
+           (htable->eq_fn(key, cursor->key))) {
+           return cursor->value;
+       }
+    
+       cursor = cursor->next;
+    }
+  
+    return (addr_t)NULL;
+}
+
+
+/* returns value associated with key */
+addr_t palacios_htable_remove(struct hashtable * htable, addr_t key, int free_key) {
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+  
+    struct hash_entry * cursor;
+    struct hash_entry ** entry_ptr;
+    addr_t value;
+    uint_t hash_value;
+    uint_t index;
+  
+    hash_value = do_hash(htable, key);
+
+    index = indexFor(htable->table_length, hash_value);
+
+    entry_ptr = &(htable->table[index]);
+    cursor = *entry_ptr;
+
+    while (cursor != NULL) {
+       /* Check hash value to short circuit heavier comparison */
+       if ((hash_value == cursor->hash) && 
+           (htable->eq_fn(key, cursor->key))) {
+     
+           *entry_ptr = cursor->next;
+           htable->entry_count--;
+           value = cursor->value;
+      
+           if (free_key) {
+               freekey((void *)(cursor->key));
+           }
+           kfree(cursor);
+      
+           return value;
+       }
+
+       entry_ptr = &(cursor->next);
+       cursor = cursor->next;
+    }
+    return (addr_t)NULL;
+}
+
+
+/* destroy */
+void palacios_free_htable(struct hashtable * htable, int free_values, int free_keys) {
+    uint_t i;
+    struct hash_entry * cursor;
+    struct hash_entry * tmp;
+    struct hash_entry **table = htable->table;
+
+    if (free_values) {
+       for (i = 0; i < htable->table_length; i++) {
+           cursor = table[i];
+      
+           while (cursor != NULL) { 
+               tmp = cursor; 
+               cursor = cursor->next; 
+
+               if (free_keys) {
+                   freekey((void *)(tmp->key)); 
+               }
+               kfree((void *)(tmp->value)); 
+               kfree(tmp); 
+           }
+       }
+    } else {
+       for (i = 0; i < htable->table_length; i++) {
+           cursor = table[i];
+
+           while (cursor != NULL) { 
+               struct hash_entry * tmp;
+
+               tmp = cursor; 
+               cursor = cursor->next; 
+       
+               if (free_keys) {
+                   freekey((void *)(tmp->key)); 
+               }
+               kfree(tmp); 
+           }
+       }
+    }
+  
+    kfree(htable->table);
+    kfree(htable);
+}
+
diff --git a/linux_module/palacios-hashtable.h b/linux_module/palacios-hashtable.h
new file mode 100644 (file)
index 0000000..3d46202
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef __PALACIOS_HASHTABLE_H__
+#define __PALACIOS_HASHTABLE_H__
+
+struct hashtable;
+
+#define __32BIT__
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      static uint_t         hash_from_key_fn( void *k );
+ *      static int                  keys_equal_fn ( void *key1, void *key2 );
+ *
+ *      h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ * 
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ * 
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+typedef unsigned char uchar_t;
+typedef unsigned int uint_t;
+typedef unsigned long long ullong_t;
+typedef unsigned long ulong_t;
+typedef ulong_t addr_t;
+
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype)            \
+    static int fnname (struct hashtable * htable, keytype key, valuetype value) { \
+       return v3_htable_insert(htable, (addr_t)key, (addr_t)value);    \
+    }
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype)            \
+    static valuetype * fnname (struct hashtable * htable, keytype  key) { \
+       return (valuetype *) (v3_htable_search(htable, (addr_t)key));   \
+    }
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype, free_key)  \
+    static valuetype * fnname (struct hashtable * htable, keytype key) { \
+       return (valuetype *) (v3_htable_remove(htable, (addr_t)key, free_key)); \
+    }
+
+
+
+
+
+/* These cannot be inlined because they are referenced as fn ptrs */
+ulong_t palacios_hash_long(ulong_t val, uint_t bits);
+ulong_t palacios_hash_buffer(uchar_t * msg, uint_t length);
+
+
+
+struct hashtable * palacios_create_htable(uint_t min_size,
+                                   uint_t (*hashfunction) (addr_t key),
+                                   int (*key_eq_fn) (addr_t key1, addr_t key2));
+
+void palacios_free_htable(struct hashtable * htable, int free_values, int free_keys);
+
+/*
+ * returns non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+int palacios_htable_insert(struct hashtable * htable, addr_t key, addr_t value);
+
+int palacios_htable_change(struct hashtable * htable, addr_t key, addr_t value, int free_value);
+
+
+// returns the value associated with the key, or NULL if none found
+addr_t palacios_htable_search(struct hashtable * htable, addr_t key);
+
+// returns the value associated with the key, or NULL if none found
+addr_t palacios_htable_remove(struct hashtable * htable, addr_t key, int free_key);
+
+uint_t palacios_htable_count(struct hashtable * htable);
+
+// Specialty functions for a counting hashtable 
+int palacios_htable_inc(struct hashtable * htable, addr_t key, addr_t value);
+int palacios_htable_dec(struct hashtable * htable, addr_t key, addr_t value);
+
+
+#endif
diff --git a/linux_module/palacios-host-dev-user.h b/linux_module/palacios-host-dev-user.h
new file mode 100644 (file)
index 0000000..54b2e17
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef _PALACIOS_HOST_DEV_USER_H_
+#define _PALACIOS_HOST_DEV_USER_H_
+
+/*
+ * Palacios Host Device Interface + User-space interface 
+ * (c) Peter Dinda, 2011
+ */
+
+
+#define V3_VM_HOST_DEV_CONNECT 512+1
+
+/* to detemine whether a host request is available, poll the fd for read */
+
+/* make a request for reading/writing guest or injecting irq */
+/* the arguemnt is a pointer to a palacios_host_dev_user_op struct */
+/* return is negative on error, positive to indicate bytes read/written or irq injected*/
+#define V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL  1
+
+/* find out the size of the current host request, if one is pending */
+/* you find out if one is pending by read poll/select on the fd */
+/* the argument is a pointer to a uint64_t that will give the total size */
+/* ioctl returns 1 if a request is ready, 0 if there is no request */
+/* -EFAULT if there is a an error */
+#define V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL  2
+
+/* get the current host request, if one is available */
+/* the argument is a pointer to a palacios_host_dev_host_request_response */
+/* of the needed size */
+/* ioctl returns 1 if a request is ready+copied, 0 if there is no request */
+/* -EFAULT if there is a an error */
+#define V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL  3
+
+/* write back the response to the previously pulled host request */
+/* the argument is a pointer to a palacios_host_dev_host_request_response */
+#define V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL 4
+
+
+#ifdef __KERNEL__
+#define USER __user
+#else
+#define USER
+#endif
+
+struct palacios_host_dev_user_op {
+#define PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST  1
+#define PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST 2
+#define PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST   3
+    uint32_t        type;   // type of operation (from the #defs above)
+    void            *gpa;   // physical address in guest to read or write
+    void USER      *data;   // user address of data that will be read or written
+    uint64_t        len;    // number of bytes to move
+
+    uint8_t         irq;    // irq to inject
+};
+
+
+struct palacios_host_dev_host_request_response {
+    // data_len must remain the first field in this structure
+    uint64_t  data_len;    // size of the structure + occupied data
+    uint64_t  len;         // size of the structure in total
+#define PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO     1
+#define PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO    2
+#define PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM    3
+#define PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM   4
+#define PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF   5
+#define PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF  6
+    uint32_t  type;        // one of the types given above
+    uint16_t  port;        // port number, for IO
+    void      *gpa;         // physical address in the guest for memory ops
+    uint64_t  conf_addr;   // address in the configuration for configuration ops
+
+    uint64_t  op_len;      // response: bytes read/written to the device
+                           // request: bytes to read/write
+                            
+    uint8_t   data[0];     // data (if any)
+
+} ;
+
+
+
+#endif
diff --git a/linux_module/palacios-host-dev.c b/linux_module/palacios-host-dev.c
new file mode 100644 (file)
index 0000000..686c962
--- /dev/null
@@ -0,0 +1,1017 @@
+/* 
+ * Host device interface + user-space device interface
+ * (c) 2011 Peter Dinda
+ */
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <interfaces/vmm_host_dev.h>
+
+#include "palacios.h"
+#include "palacios-host-dev.h"
+#include "palacios-host-dev-user.h"
+
+
+
+/*
+  There are two things in this file:
+
+
+  1. An implementation of the Palacios host device interface that will
+     accept any URL from Palacios.  Currently, the only URL type it will
+     handle is user:<name>, but it should be clear how to extend with
+     other types.
+
+     Palacios opens a host device by issuing something like this:
+
+         palacios_host_dev_open( impl="user:foo" busclass=pci, opaque )
+
+     This will attempt to rendezvous with the user space device The
+     rendevzous retry and timeout periods can be set below.
+
+  2. An implementation of user: urls - the host interface is mapped
+     into an RPC-like interface to/from user space via a file
+     interface.   
+
+     The user space gets a file descriptor like this:
+
+     int vmfd = open("/dev/v3-vmX",...);
+
+     int devfd = ioctl(vmfd,V3_HOST_DEV_CONNECT,"user:foo"); 
+
+     This will attempt to rendezvous with the host side.
+
+     If it returns successfully, you can now issue synchronous,
+     blocking RPCs to the guest to read/write its memory and inject
+     irqs.  This means that a user->host request is handled
+     immediately, and independently of any host->user request. 
+
+     struct palacios_host_dev_user_op op;
+
+     // fill out op
+     op.type = PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST; 
+     ...
+
+     ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL, &op);
+
+     // return value is # bytes read or written; or 0 if irq injected
+     // negative value is error
+
+     The interface from the host to the user side is asynchronous
+     blocking RPC.  Any host device will have at most one outstanding
+     request from palacios.  The implementation here stores the
+     request until the user side is ready to accept it.  The user side
+     can check if there is a request via a poll/select or an ioctl.
+     The ioctl also returns the needed size for the request structure.
+     After the user side has a request, it is expected to process it,
+     perhaps making user->host requests as described above, and then
+     return a response.  Only one host->user request should be in
+     progress at any time in the user space.
+
+     What this looks like is:
+     
+     poll(...devfd for read...) or select(...devfd for read...)
+
+     if (devfd is marked readable) { 
+         uint64_t size;
+
+         ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&size);
+         // returns 1 if there is a request, 0 if not, negative on err
+
+         struct palacios_host_dev_host_request_response *req;
+
+         req = allocate req to be at least size bytes long
+
+         ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,req)
+         // returns 1 if there is a request, 0 if not, negative on err
+        
+         // process request, perhaps using above user->host request
+         // build response structure
+         // resp.data_len == size of structure including relevant data at end
+
+         ioctl(devfd,V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL,resp);
+        // returns 0 if there is no outstanding request (user error)
+        // 1 on success, negative on error
+     }
+    
+
+*/
+
+
+#define MAX_URL 256
+
+#define RENDEZVOUS_WAIT_SECS  60
+#define RENDEZVOUS_RETRY_SECS 1
+
+
+struct palacios_host_device_user {
+    spinlock_t lock;
+    int      connected;    // is the user space connected to this?
+    int      waiting;      // am I waiting for a user-space response?
+
+    int      fd;           // what is the user space fd?
+
+    char     url[MAX_URL]; // what is the url describing the device
+
+    v3_guest_dev_t guestdev; // what is the palacios-side device
+
+    wait_queue_head_t  user_wait_queue; // user space processes waiting on us (should be only one)
+    wait_queue_head_t  host_wait_queue; // host threads (should only be one) waiting on user space
+
+    struct v3_guest                                *guest; // my guest
+    struct palacios_host_dev_host_request_response *req;   // curent request
+    struct palacios_host_dev_host_request_response *resp;  // curent response
+
+    struct list_head  node;   // for adding me to the list of hostdevs this VM has
+};
+
+
+/**************************************************************************************
+  Utility functions
+*************************************************************************************/
+
+static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
+{
+    if (dev->req) {
+       kfree(dev->req);
+       dev->req=0;
+    } 
+    if (dev->resp) { 
+       kfree(dev->resp);
+       dev->resp=0;
+    }
+    kfree(dev);
+}
+
+static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy)
+{
+    if (!*r) { 
+       // allocate it
+       *r = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
+       if (!*r) { 
+           return -1;
+       } else {
+           (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
+           return 0;
+       }
+    } else {
+       //let it go if it's big enough
+       uint64_t cur_len = (*r)->len-sizeof(struct palacios_host_dev_host_request_response);
+
+       if (data_size<=cur_len) { 
+           // do nothing
+           return 0;
+       } else {
+           struct palacios_host_dev_host_request_response *new;
+
+           if (!copy) { 
+               kfree(*r);
+               *r=0;
+           }
+           new = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
+           if (!new) { 
+               return -1;
+           } else {
+               new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
+               if (copy) { 
+                   memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
+                   new->data_len=(*r)->data_len;
+                   kfree(*r);
+               }
+               *r=new;
+               return 0;
+           }
+       }
+    }
+}
+
+static void cycle_request_response(struct palacios_host_device_user *dev)
+{
+    // wake up user side so that polls fall through
+    wake_up_interruptible(&(dev->user_wait_queue));
+    // put us to sleep until the user side wakes us up
+    wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0));
+}
+
+static void cycle_response_request(struct palacios_host_device_user *dev)
+{
+    // wake up host side
+    wake_up_interruptible(&(dev->host_wait_queue));
+}
+
+    
+/*********************************************************************************************
+
+    Interface to user space
+
+ *********************************************************************************************/ 
+
+
+
+static unsigned int host_dev_poll(struct file * filp, 
+                                 struct poll_table_struct * poll_tb) 
+{
+
+    struct palacios_host_device_user * dev = filp->private_data;
+    unsigned long f;
+
+    if (!dev->connected) { 
+       return -EFAULT;
+    }
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    if (dev->waiting) { 
+       // Yes, we have a request if you want it!
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return  POLLIN | POLLRDNORM;
+    } 
+
+    // No request yet, so we need to wait for one to show up.
+
+    // register ourselves on the user wait queue
+    poll_wait(filp, &(dev->user_wait_queue), poll_tb);
+
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // We will get called again when that queue is woken up
+
+    return 0;
+}
+
+
+static int host_dev_release(struct inode * i, struct file * filp) 
+{
+    struct palacios_host_device_user *dev = filp->private_data;
+    unsigned long f;
+
+    printk("palacios: user side is closing host device \"%s\"\n",dev->url);
+    
+    spin_lock_irqsave(&(dev->lock), f);
+    dev->connected = 0;
+    spin_unlock_irqrestore(&(dev->lock), f);
+
+    // it is the palacios->host interface's responsibility to ignore
+    // reads/writes until connected is true
+
+    return 0;
+}
+
+static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, unsigned long arg)
+{
+    void __user *argp = (void __user *)arg;
+
+    struct palacios_host_device_user *dev = fp->private_data;
+
+    if (!dev->connected) { 
+       return -EFAULT;
+    }
+    
+    switch (val) { 
+       case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
+           
+           struct palacios_host_dev_user_op op;
+           
+           if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { 
+               printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
+               return -EFAULT;
+           }
+           
+           switch (op.type) { 
+               case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
+                   void *temp = kmalloc(op.len,GFP_KERNEL);
+
+                   if (!temp) { 
+                       printk("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
+                       return -EFAULT;
+                   }
+                   
+                   if (v3_host_dev_read_guest_mem(dev->guestdev,
+                                                  dev,
+                                                  op.gpa,
+                                                  temp,
+                                                  op.len) != op.len) {
+                       printk("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
+                       kfree(temp);
+                       return -EFAULT;
+                   }
+                   
+                   if (copy_to_user(op.data,temp,op.len)) { 
+                       printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
+                       kfree(temp);
+                       return -EFAULT;
+                   }
+
+                   kfree(temp);
+
+                   return op.len;
+               }
+                   break;
+                   
+
+               case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
+
+                   void *temp = kmalloc(op.len,GFP_KERNEL);
+
+                   if (!temp) { 
+                       printk("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
+                       return -EFAULT;
+                   }
+                   
+                   if (copy_from_user(temp,op.data,op.len)) { 
+                       printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
+                       kfree(temp);
+                       return -EFAULT;
+                   }
+                   
+                   if (v3_host_dev_write_guest_mem(dev->guestdev,
+                                                   dev,
+                                                   op.gpa,
+                                                   temp,
+                                                   op.len) != op.len) {
+                       printk("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
+                       kfree(temp);
+                       return -EFAULT;
+                   }
+
+                   kfree(temp);
+                   
+                   return op.len;
+               }
+                   break;
+
+               case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
+
+                   return  v3_host_dev_raise_irq(dev->guestdev, dev, op.irq);
+               }
+                   break;
+
+               default:
+                   printk("palacios: unknown user request to host device \"%s\"\n",dev->url);
+                   return -EFAULT;
+                   break;
+           }
+       }
+           break;
+
+       case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
+           
+           unsigned long f;
+           
+           spin_lock_irqsave(&(dev->lock),f);
+           
+           if (!(dev->waiting)) { 
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return 0; // no request available now
+           } 
+           
+           if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
+               printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return -EFAULT; // failed to copy!
+           }
+           
+           spin_unlock_irqrestore(&(dev->lock),f);
+           
+           return 1; // have request for you
+           
+       }
+           
+           break;
+           
+       case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
+           
+           unsigned long f;
+           
+           spin_lock_irqsave(&(dev->lock),f);
+           
+           if (!(dev->waiting)) { 
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return 0; // no request available now
+           } 
+           
+           if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
+               printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return -EFAULT; // failed to copy!
+           }
+           
+           spin_unlock_irqrestore(&(dev->lock),f);
+           
+           return 1; // copied request for you
+       }
+           break;
+           
+       case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
+
+           unsigned long f;
+           uint64_t user_datalen;
+           
+           spin_lock_irqsave(&(dev->lock),f);
+           
+           if (!(dev->waiting)) { 
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return 0; // no request outstanding, so we do not need a response!
+           }
+           
+           if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
+               printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return -EFAULT; // failed to copy!
+           } 
+           
+           if (palacios_resize_reqresp(&(dev->resp),user_datalen,0)) {
+               printk("palacios: unable to resize to accept request of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return -EFAULT;
+           } 
+           
+           if (copy_from_user(dev->resp, argp, user_datalen)) { 
+               printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
+               spin_unlock_irqrestore(&(dev->lock),f);
+               return -EFAULT; // failed to copy!
+           } 
+           
+           // now have valid response!
+           dev->waiting=0;
+
+           // wake the palacios side up so that it sees it
+           cycle_response_request(dev);
+
+           spin_unlock_irqrestore(&(dev->lock),f);
+
+           return 1; // done
+       }
+           break;
+           
+       default:
+           printk("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
+           return -EFAULT;
+           break;
+    }
+    
+}
+
+
+static struct file_operations host_dev_fops = {
+    .poll     = host_dev_poll,
+    .release  = host_dev_release,
+    .ioctl    = host_dev_ioctl,
+};
+
+
+
+    
+int connect_host_dev(struct v3_guest * guest, char *url) 
+{
+    struct palacios_host_device_user *dev;
+    unsigned long f1, f2;
+    int i;
+
+    // currently only support user: types:
+    if (strncasecmp(url,"user:",5)) { 
+       printk("palacios: do not currently support host devices of type in \"%s\"\n",url);
+       return -1;
+    }
+    
+    printk("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
+    
+    // We will scan the list looking for the relevant
+    // URL.  If we don't find it after a while, we give up
+    
+    for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
+       spin_lock_irqsave(&(guest->hostdev.lock),f1);
+       list_for_each_entry(dev,&(guest->hostdev.devs), node) {
+           if (!strncasecmp(url,dev->url,MAX_URL)) { 
+               // found it
+               spin_lock_irqsave(&(dev->lock),f2);
+               if (dev->connected) { 
+                   printk("palacios: device for \"%s\" is already connected!\n",url);
+                   spin_unlock_irqrestore(&(dev->lock),f2);
+                   spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+                   return -1;
+               } else {
+                   dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
+                   if (dev->fd<0) { 
+                       printk("palacios: cannot create fd for device \"%s\"\n",url);
+                       spin_unlock_irqrestore(&(dev->lock),f2);
+                       spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+                       return -1;
+                   }
+                   dev->connected=1;
+                   dev->waiting=0;
+                   if (dev->req) { 
+                       kfree(dev->req);
+                       dev->req=0;
+                   } 
+                   if (dev->resp) { 
+                       kfree(dev->resp);
+                       dev->resp=0;
+                   }
+                   printk("palacios: connected fd for device \"%s\"\n",url);
+                   spin_unlock_irqrestore(&(dev->lock),f2);
+                   spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+                   return dev->fd;
+               }
+               spin_unlock_irqrestore(&(dev->lock),f2);
+           }
+       }
+       spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+       
+       ssleep(RENDEZVOUS_RETRY_SECS);
+    }
+    
+    printk("palacios: timeout waiting for connection for device \"%s\"",url);
+    
+    return -1;
+    
+}
+
+
+
+
+
+
+
+
+/***************************************************************************************
+
+   Following this is the implementation of the palacios->host interface
+
+**************************************************************************************/
+
+static v3_host_dev_t palacios_host_dev_open(char *url,
+                                           v3_bus_class_t bus,
+                                           v3_guest_dev_t gdev,
+                                           void *host_priv_data)
+{
+    struct v3_guest *guest= (struct v3_guest*)host_priv_data;
+    struct palacios_host_device_user *dev;
+    unsigned long f1,f2;
+    int i;
+
+    /*
+      I will create the device in the list and then wait
+      for the user side to attach
+    */
+
+
+    if (strncasecmp(url,"user:",5)) { 
+       printk("palacios: do not currently support devices of type in \"%s\"\n",url);
+       return NULL;
+    }
+
+    // Check to see if a device of this url already exists, which would be ugly
+    spin_lock_irqsave(&(guest->hostdev.lock),f1);
+    list_for_each_entry(dev,&(guest->hostdev.devs), node) {
+       if (!strncasecmp(url,dev->url,MAX_URL)) { 
+           // found it
+           spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+           printk("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
+           return NULL;
+       }
+    }
+    spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+
+
+    printk("palacios: creating host device \"%s\"\n",url);
+
+    dev = kmalloc(sizeof(struct palacios_host_device_user),GFP_KERNEL);
+    
+    if (!dev) { 
+       printk("palacios: cannot allocate for host device \"%s\"\n",url);
+       return NULL;
+    }
+
+    memset(dev,0,sizeof(struct palacios_host_device_user));
+    
+    strncpy(dev->url,url,MAX_URL);
+    
+    dev->guestdev=gdev;
+    
+    dev->guest=guest;
+
+    spin_lock_init(&(dev->lock));
+
+    init_waitqueue_head(&(dev->user_wait_queue));
+    init_waitqueue_head(&(dev->host_wait_queue));
+
+    printk("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url);
+    
+    // Insert ourselves into the list
+    spin_lock_irqsave(&(guest->hostdev.lock),f1);
+    list_add(&(dev->node),&(guest->hostdev.devs));
+    spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+
+    
+    // Now wait until we are noticed!
+    for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
+       spin_lock_irqsave(&(dev->lock),f2);
+       if (dev->connected){ 
+           printk("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
+           spin_unlock_irqrestore(&(dev->lock),f2);
+           return dev;
+       }
+       spin_unlock_irqrestore(&(dev->lock),f2);
+       ssleep(RENDEZVOUS_RETRY_SECS);
+    }
+    
+    printk("palacios: timeout waiting for user side to connect to host device \"%s\"",url);
+    
+    // get us out of the list
+    spin_lock_irqsave(&(guest->hostdev.lock),f1);
+    list_del(&(dev->node));
+    spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+    
+    palacios_host_dev_user_free(dev);
+    
+    return NULL;
+}
+
+static int palacios_host_dev_close(v3_host_dev_t hostdev)
+{
+    unsigned long f1, f2;
+
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
+    
+    printk("palacios: closing host device \"%s\"\n",dev->url);
+
+    spin_lock_irqsave(&(dev->guest->hostdev.lock),f1);
+
+    spin_lock_irqsave(&(dev->lock),f2);
+
+    if (dev->connected) { 
+       dev->connected=0;
+       // After this, any user side request will return -EFAULT
+    }
+
+    list_del(&(dev->node));
+    
+    spin_unlock_irqrestore(&(dev->lock),f2);
+    spin_unlock_irqrestore(&(dev->guest->hostdev.lock),f1);
+    
+    palacios_host_dev_user_free(dev);
+
+    return 0;
+}
+
+
+
+       
+static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
+                                         uint16_t      port,
+                                         void          *dest,
+                                         uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
+    dev->req->port=port;
+    dev->req->op_len=len;
+    dev->req->gpa=0;
+    dev->req->conf_addr=0;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    memcpy(dest,dev->resp->data, op_len);
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+}
+
+static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
+                                          void *        gpa,
+                                          void          *dest,
+                                          uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
+    dev->req->port=0;
+    dev->req->op_len=len;
+    dev->req->gpa=gpa;
+    dev->req->conf_addr=0;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    memcpy(dest,dev->resp->data, op_len);
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+}
+
+static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
+                                           uint64_t      offset,
+                                           void          *dest,
+                                           uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
+    dev->req->port=0;
+    dev->req->op_len=len;
+    dev->req->gpa=0;
+    dev->req->conf_addr=offset;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    memcpy(dest,dev->resp->data, op_len);
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+}
+
+
+static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
+                                          uint16_t      port,
+                                          void          *src,
+                                          uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued i/o write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),len,0); // make room for data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
+    dev->req->port=port;
+    dev->req->op_len=len;
+    dev->req->gpa=0;
+    dev->req->conf_addr=0;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
+
+    memcpy(dev->req->data,src,len);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+}
+
+
+static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
+                                           void *        gpa,
+                                           void          *src,
+                                           uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),len,0); // make room for data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
+    dev->req->port=0;
+    dev->req->op_len=len;
+    dev->req->gpa=gpa;
+    dev->req->conf_addr=0;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
+
+    memcpy(dev->req->data,src,len);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+}
+
+
+static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
+{
+    // we don't care
+    return 0;
+}
+
+
+static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
+                                            uint64_t      offset,
+                                            void          *src,
+                                            uint64_t      len)
+{
+    struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
+    unsigned long f;
+    uint64_t op_len;
+
+    spin_lock_irqsave(&(dev->lock),f);
+    
+    if (dev->waiting) { 
+       printk("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    if (!dev->connected) {
+       printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+       spin_unlock_irqrestore(&(dev->lock),f);
+       return 0;
+    }
+    
+    // resize request and response in case they will need it
+    palacios_resize_reqresp(&(dev->req),len,0); // make room for data
+
+    dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
+    dev->req->port=0;
+    dev->req->op_len=len;
+    dev->req->gpa=0;
+    dev->req->conf_addr=offset;
+    dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
+
+    memcpy(dev->req->data,src,len);
+
+    dev->waiting=1;
+    
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    // hand over to the user space and wait for it to respond
+    cycle_request_response(dev);
+
+    // We're back!   So now we'll hand the response back to Palacios
+
+    spin_lock_irqsave(&(dev->lock),f);
+
+    op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
+
+    spin_unlock_irqrestore(&(dev->lock),f);
+
+    return op_len;
+ }
+
+
+
+
+static struct v3_host_dev_hooks palacios_host_dev_hooks = {
+    .open                      = palacios_host_dev_open,
+    .close                      = palacios_host_dev_close,
+    .read_io                    = palacios_host_dev_read_io,
+    .write_io                   = palacios_host_dev_write_io,
+    .read_mem                   = palacios_host_dev_read_mem,
+    .write_mem                  = palacios_host_dev_write_mem,
+    .read_config                = palacios_host_dev_read_conf,
+    .write_config               = palacios_host_dev_write_conf,
+    .ack_irq                    = palacios_host_dev_ack_irq,
+};
+
+
+
+int palacios_init_host_dev( void ) {
+    V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
+    
+    return 0;
+}
diff --git a/linux_module/palacios-host-dev.h b/linux_module/palacios-host-dev.h
new file mode 100644 (file)
index 0000000..d444b7d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Palacios Host Device Interface + User-space interface 
+ * (c) Peter Dinda, 2011
+ */
+
+#ifndef __PALACIOS_HOST_DEV_H__
+#define __PALACIOS_HOST_DEV_H__
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include "palacios-host-dev-user.h"
+
+struct v3_guest;
+
+/*
+   This is the collection of host devices that
+   a single guest has
+*/
+struct palacios_host_dev {
+    spinlock_t      lock;
+    struct list_head devs;
+};
+
+
+
+int connect_host_dev(struct v3_guest * guest, char *url);
+
+int palacios_init_host_dev( void );
+
+
+#endif
diff --git a/linux_module/palacios-keyed-stream.c b/linux_module/palacios-keyed-stream.c
new file mode 100644 (file)
index 0000000..b3fbe2b
--- /dev/null
@@ -0,0 +1,297 @@
+#include "palacios.h"
+#include "palacios-keyed-stream.h"
+#include "palacios-hashtable.h"
+
+#define sint64_t int64_t
+#include <interfaces/vmm_keyed_stream.h>
+
+/*
+  Streams are stored in a hash table
+  The values for this hash table are hash tables associted with 
+  each stream.   A keyed stream for a "mem:" stream is 
+  an instance of the structure given here 
+*/
+
+#define DEF_NUM_STREAMS 16
+#define DEF_NUM_KEYS    128
+#define DEF_SIZE        128
+
+struct mem_stream {
+    char     *data;
+    uint32_t  size;
+    uint32_t  data_max;
+    uint32_t  ptr;
+};
+
+static struct mem_stream *create_mem_stream(void)
+{
+    struct mem_stream *m = kmalloc(sizeof(struct mem_stream),GFP_KERNEL);
+
+    if (!m) {
+       return 0;
+    }
+
+    m->data = kmalloc(DEF_SIZE,GFP_KERNEL);
+    
+    if (!m->data) { 
+       kfree(m);
+       return 0;
+    }
+
+    m->size=DEF_SIZE;
+    m->ptr=0;
+    m->data_max=0;
+    
+    return m;
+}
+
+static void destroy_mem_stream(struct mem_stream *m)
+{
+    if (m) {
+       if (m->data) {
+           kfree(m->data);
+       }
+       m->data=0;
+       kfree(m);
+    }
+}
+    
+static int expand_mem_stream(struct mem_stream *m, uint32_t new_size)
+{
+    void *data = kmalloc(new_size,GFP_KERNEL);
+    uint32_t nc;
+
+    if (!data) { 
+       return -1;
+    }
+    
+    nc = (new_size<m->data_max) ? new_size : m->data_max;
+
+    memcpy(data,m->data,nc);
+
+    kfree(m->data);
+
+    m->data=data;
+    m->size=new_size;
+    if (m->size<m->data_max) { 
+       m->data_max=m->size;
+    }
+   
+    return 0;
+}
+
+static uint32_t write_mem_stream(struct mem_stream *m,
+                                void *data,
+                                uint32_t len)
+{
+    if ((m->ptr + len) > m->size) { 
+       if (expand_mem_stream(m,m->ptr + len)) { 
+           return 0;
+       }
+    }
+    memcpy(m->data+m->ptr,data,len);
+    m->ptr+=len;
+    m->data_max=m->ptr;
+    
+    return len;
+
+}
+
+static uint32_t read_mem_stream(struct mem_stream *m,
+                               void *data,
+                               uint32_t len)
+{
+    if ((m->ptr + len) > m->data_max) { 
+       return 0;
+    }
+    memcpy(data,m->data+m->ptr,len);
+    m->ptr+=len;
+    
+    return len;
+
+}
+
+
+static void reset_mem_stream(struct mem_stream *m)
+{
+    m->ptr=0;
+}
+
+
+static inline uint_t hash_func(addr_t key)
+{
+    return palacios_hash_buffer((uchar_t*)key,strlen((uchar_t*)key));
+}
+
+static inline int hash_comp(addr_t k1, addr_t k2)
+{
+    return strcasecmp((char*)k1,(char*)k2)==0;
+}
+
+
+// This stores all the streams
+static struct hashtable *streams=0;
+
+
+static v3_keyed_stream_t open_stream(char *url,
+                                    v3_keyed_stream_open_t ot)
+{
+    if (strncasecmp(url,"mem:",4)) { 
+       printk("Only in-memory streams are currently supported\n");
+       return 0;
+    }
+
+    switch (ot) { 
+       case V3_KS_RD_ONLY:
+       case V3_KS_WR_ONLY:
+           return (v3_keyed_stream_t) palacios_htable_search(streams,(addr_t)(url+4));
+           break;
+       case V3_KS_WR_ONLY_CREATE: {
+           struct hashtable *s = (struct hashtable *) palacios_htable_search(streams,(addr_t)(url+4));
+
+           if (!s) { 
+                s = palacios_create_htable(DEF_NUM_KEYS,hash_func,hash_comp);
+                if (!s) { 
+                    printk("Cannot allocate in-memory keyed stream %s\n",url);
+                    return 0;
+                }
+                if (!palacios_htable_insert(streams,(addr_t)(url+4),(addr_t)s)) { 
+                    printk("Cannot insert in-memory keyed stream %s\n",url);
+                    return 0;
+                }
+           }
+
+           return s;
+           
+       }
+
+           break;
+    }
+    
+    return 0;
+    
+}
+
+
+static void close_stream(v3_keyed_stream_t stream)
+{
+    // nothing to do
+    return;
+}
+
+static v3_keyed_stream_key_t open_key(v3_keyed_stream_t stream,
+                                     char *key)
+{
+    struct hashtable *s = (struct hashtable *) stream;
+
+    struct mem_stream *m;
+
+    m = (struct mem_stream *) palacios_htable_search(s,(addr_t)key);
+
+    if (!m) { 
+       m = create_mem_stream();
+       
+       if (!m) { 
+           printk("Cannot allocate keyed stream for key %s\n",key);
+           return 0;
+       }
+
+       if (!palacios_htable_insert(s,(addr_t)key,(addr_t)m)) {
+           printk("Cannot insert keyed stream for key %s\n",key);
+           destroy_mem_stream(m);
+           return 0;
+       }
+    }
+
+    reset_mem_stream(m);
+    return m;
+
+}
+
+static void close_key(v3_keyed_stream_t stream, 
+                     v3_keyed_stream_key_t key)
+{
+    // nothing to do
+    return;
+}
+
+static sint64_t write_key(v3_keyed_stream_t stream, 
+                         v3_keyed_stream_key_t key,
+                         void *buf,
+                         sint64_t len)
+{
+    struct mem_stream *m = (struct mem_stream *) key;
+    uint32_t mylen;
+    uint32_t writelen;
+
+    if (len<0) { 
+       return len;
+    }
+    
+    mylen = (uint32_t) len;
+
+    writelen=write_mem_stream(m,buf,mylen);
+
+    if (writelen!=mylen) { 
+       printk("Failed to write all data for key\n");
+       return -1;
+    } else {
+       return (sint64_t)writelen;
+    }
+}
+
+static sint64_t read_key(v3_keyed_stream_t stream, 
+                        v3_keyed_stream_key_t key,
+                        void *buf,
+                        sint64_t len)
+{
+    struct mem_stream *m = (struct mem_stream *) key;
+    uint32_t mylen;
+    uint32_t readlen;
+    
+    if (len<0) { 
+       return len;
+    }
+    
+    mylen = (uint32_t) len;
+
+    readlen=read_mem_stream(m,buf,mylen);
+
+    if (readlen!=mylen) { 
+       printk("Failed to read all data for key\n");
+       return -1;
+    } else {
+       return (sint64_t)readlen;
+    }
+}
+    
+static struct v3_keyed_stream_hooks hooks = {
+    .open = open_stream,
+    .close = close_stream,
+    .open_key = open_key,
+    .close_key = close_key,
+    .read_key = read_key,
+    .write_key = write_key
+};
+
+
+int palacios_init_keyed_streams()
+{
+    streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
+
+    if (!streams) { 
+       printk("Failed to allocated stream pool\n");
+       return -1;
+    }
+
+    V3_Init_Keyed_Streams(&hooks);
+    
+    return 0;
+
+}
+
+int palacios_deinit_keyed_streams()
+{
+    printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY!\n");
+    return -1;
+}
diff --git a/linux_module/palacios-keyed-stream.h b/linux_module/palacios-keyed-stream.h
new file mode 100644 (file)
index 0000000..218ed51
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Palacios VM Keyed Stream Interface (for checkpoint/restore)
+ * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
+ */
+
+#ifndef __PALACIOS_KEYED_STREAM_H__
+#define __PALACIOS_KEYED_STREAM_H__
+
+
+
+int palacios_init_keyed_streams(void);
+int palacios_deinit_keyed_streams(void);
+
+
+#endif
index 7380285..6f65df6 100644 (file)
 #include "palacios-inspector.h"
 #endif
 
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
+#include "palacios-graphics-console.h"
+#endif
+
+#ifdef V3_CONFIG_HOST_DEVICE
+#include "palacios-host-dev.h"
+#endif
 
 extern struct class * v3_class;
 #define STREAM_NAME_LEN 128
@@ -82,6 +89,40 @@ static long v3_vm_ioctl(struct file * filp,
            break;
        }
 
+       case V3_VM_HOST_DEV_CONNECT: {
+#ifdef V3_CONFIG_HOST_DEV
+           if (copy_from_user(host_dev_url, argp, HOST_DEV_URL_LEN)) {
+               printk("copy from user error getting url for host device connect...\n");
+               return -EFAULT;
+           }
+
+           return connect_host_dev(guest,host_dev_url);
+#else
+           printk("palacios: Host device support not available\n");
+           return -EFAULT;
+#endif
+           break;
+       }
+
+       case V3_VM_FB_INPUT: 
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
+           return palacios_graphics_console_user_input(&(guest->graphics_console),
+                                                       (struct v3_fb_input __user *) arg) ;
+#else
+           return -EFAULT;
+#endif
+           break;
+           
+       case V3_VM_FB_QUERY: 
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
+           return palacios_graphics_console_user_query(&(guest->graphics_console),
+                                                       (struct v3_fb_query_response __user *) arg);
+#else
+           return -EFAULT;
+#endif
+           break;
+
+
        default: 
            printk("\tUnhandled\n");
            return -EINVAL;
index c0e3ba2..b161832 100644 (file)
 #include "palacios-console.h"
 #endif
 
+#ifdef V3_CONFIG_GRAPHICS_CONSOLE
+#include "palacios-graphics-console.h"
+#endif
+
+#ifdef V3_CONFIG_HOST_DEVICE
+#include "palacios-host-dev.h"
+#endif
+
+
 /* Global Control IOCTLs */
 #define V3_START_GUEST 10
 #define V3_ADD_MEMORY 50
 #define V3_VM_STREAM_CONNECT 21
 #define V3_VM_STOP 22
 
+#define V3_VM_FB_INPUT 256+1
+#define V3_VM_FB_QUERY 256+2
+
+#define V3_VM_HOST_DEV_CONNECT 512+1
+
+
 struct v3_guest_img {
     unsigned long long size;
     void * guest_data;
@@ -57,6 +72,15 @@ struct v3_guest {
     struct palacios_console console;
 #endif
 
+#ifdef V3_CONFIG_CONSOLE
+    struct palacios_graphics_console graphics_console;
+#endif
+
+#ifdef V3_CONFIG_HOST_DEVICE
+    struct palacios_host_dev hostdev;
+#endif
+
+
     struct completion start_done;
     struct completion thread_done;
 
index 2fc1ad8..c2a23aa 100644 (file)
@@ -1,4 +1,5 @@
-all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net
+all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example
+
 
 
 v3_ctrl : v3_ctrl.c v3_ctrl.h
@@ -23,5 +24,8 @@ v3_monitor : v3_cons.c v3_ctrl.h
 v3_net : v3_net.c v3_ctrl.h
        gcc -static v3_net.c -o v3_net
 
+v3_user_host_dev_example: v3_user_host_dev_example.c v3_user_host_dev.h v3_user_host_dev.c
+       gcc -static -I../linux_module v3_user_host_dev_example.c v3_user_host_dev.c -o v3_user_host_dev_example
+
 clean:
        rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net
diff --git a/linux_usr/v3_user_host_dev.c b/linux_usr/v3_user_host_dev.c
new file mode 100644 (file)
index 0000000..8fe121a
--- /dev/null
@@ -0,0 +1,123 @@
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+#include "v3_user_host_dev.h"
+
+
+int v3_user_host_dev_rendezvous(char *vmdev, char *url)
+{
+    int vmfd;
+    int devfd;
+
+    if ((vmfd=open(vmdev,O_RDWR))<0) { 
+       return -1;
+    }
+
+    devfd = ioctl(vmfd,V3_VM_HOST_DEV_CONNECT,url);
+    
+    close(vmfd);
+
+    return devfd;
+
+}
+int v3_user_host_dev_depart(int devfd)
+{
+    return close(devfd);
+}
+
+
+int v3_user_host_dev_have_request(int devfd)
+{
+    uint64_t len;
+
+    return ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len)==1;
+}
+
+int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_request_response **req)
+{
+    uint64_t len;
+    int rc;
+
+    rc=ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len);
+
+    if (rc<=0) { 
+       return -1;
+    } else {
+       struct palacios_host_dev_host_request_response *r = malloc(len);
+       
+       rc=ioctl(devfd, V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,r);
+       
+       if (rc<=0) { 
+           free(r);
+           return -1;
+       } else {
+           *req=r;
+           return 0;
+       }
+    }
+}
+               
+
+int v3_user_host_dev_push_response(int devfd, struct palacios_host_dev_host_request_response *resp)
+{
+    int rc;
+
+    rc=ioctl(devfd, V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL,resp);
+       
+    if (rc<=0) { 
+       return -1;
+    } else {
+       return 0;
+    }
+}
+               
+
+
+static uint64_t do_user(int devfd, struct palacios_host_dev_user_op *op)
+{
+    return ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL,op);
+}
+
+uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len)
+{
+    struct palacios_host_dev_user_op op;
+
+    op.type= PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST;
+    op.gpa=gpa;
+    op.data=dest;
+    op.len=len;
+    op.irq=0;
+    
+    return do_user(devfd,&op);
+}
+
+uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len)
+{
+    struct palacios_host_dev_user_op op;
+
+    op.type= PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST;
+    op.gpa=gpa;
+    op.data=src;
+    op.len=len;
+    op.irq=0;
+    
+    return do_user(devfd,&op);
+}
+
+int      v3_user_host_dev_inject_irq(int devfd, uint8_t irq)
+{
+    struct palacios_host_dev_user_op op;
+
+    op.type= PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST;
+    op.gpa=0;
+    op.data=0;
+    op.len=0;
+    op.irq=irq;
+    
+    return do_user(devfd,&op);
+}
+
+
+
diff --git a/linux_usr/v3_user_host_dev.h b/linux_usr/v3_user_host_dev.h
new file mode 100644 (file)
index 0000000..523150f
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _V3_USER_HOST_DEV_
+#define _V3_USER_HOST_DEV_
+
+#include <stdint.h>
+#include "palacios-host-dev-user.h"
+
+int v3_user_host_dev_rendezvous(char *vmdev, char *url); // returns devfd for use in poll/select
+int v3_user_host_dev_depart(int devfd);
+
+int v3_user_host_dev_have_request(int devfd);
+int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_request_response **req);
+int v3_user_host_dev_push_response(int devfd, struct palacios_host_dev_host_request_response *resp);
+
+uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
+uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
+int      v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+
+#endif
+
diff --git a/linux_usr/v3_user_host_dev_example.c b/linux_usr/v3_user_host_dev_example.c
new file mode 100644 (file)
index 0000000..833f3c5
--- /dev/null
@@ -0,0 +1,124 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/select.h>
+#include <malloc.h>
+
+#include "v3_user_host_dev.h"
+
+void usage()
+{
+    fprintf(stderr,"v3_host_dev_example /dev/v3-vm0 user:mydev busywait|select\n");
+}
+
+
+int do_work(struct palacios_host_dev_host_request_response *req, 
+           struct palacios_host_dev_host_request_response **resp)
+{
+    uint64_t datasize;
+    
+    //
+    //
+    // Process request here, perhaps calling these functions:
+    //
+    // uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
+    // uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
+    // int      v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+    //
+    // determine datasize - # bytes to include in response
+    //
+    // now built a response
+    *resp = malloc(sizeof(struct palacios_host_dev_host_request_response) + datasize);
+    (*resp)->data_len = sizeof(struct palacios_host_dev_host_request_response) + datasize;
+
+    //
+    // Fill out the fields of the response - notice that there are six kinds of things to response to:
+    //   - read/write device port
+    //   - read/write device mem
+    //   - read/write device configuration space
+
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int devfd;
+    int mode=0;
+    char *vm, *url;
+
+    if (argc!=4) { 
+       usage();
+       exit(-1);
+    }
+    
+    vm=argv[1];
+    url=argv[2];
+    mode = argv[3][0]=='s';
+
+    fprintf(stderr,"Attempting to rendezvous with host device %s on vm %s\n", url, vm);
+    
+    if ((devfd = v3_user_host_dev_rendezvous(vm,url))<0) { 
+       perror("failed to rendezvous");
+       exit(-1);
+    }
+    
+    fprintf(stderr,"Rendezvous succeeded, I will now operate in %s mode\n", mode==0 ? "busywait" : "select");
+    
+    if (mode==0) { 
+       //busywait
+
+       struct palacios_host_dev_host_request_response *req;
+       struct palacios_host_dev_host_request_response *resp;
+       uint64_t datasize;
+
+       while (1) { 
+           while (!(v3_user_host_dev_have_request(devfd))) { 
+           }
+           v3_user_host_dev_pull_request(devfd, &req);
+
+           do_work(req, &resp);
+           
+           v3_user_host_dev_push_response(devfd, resp);
+
+           free(resp);
+           free(req);
+       }
+    } else {
+
+       struct palacios_host_dev_host_request_response *req;
+       struct palacios_host_dev_host_request_response *resp;
+       uint64_t datasize;
+       fd_set   readset;
+       int rc;
+
+       // select-based operation so that you can wait for multiple things
+       
+       while (1) { 
+           FD_ZERO(&readset);
+           FD_SET(devfd,&readset);
+
+           rc = select(devfd+1, &readset, 0, 0, 0);  // pick whatever you want to select on, just include devfd
+
+           if (rc>0) { 
+               if (FD_ISSET(devfd,&readset)) { 
+                   // a request is read for us!
+                   v3_user_host_dev_pull_request(devfd, &req);
+
+                   do_work(req, &resp);
+                   
+                   v3_user_host_dev_push_response(devfd, resp);
+                   
+                   free(resp);
+                   free(req);
+               }
+           }
+       }
+    }
+
+    v3_user_host_dev_depart(devfd);
+
+    return 0;
+                   
+}
diff --git a/linux_usr/x0vncserver b/linux_usr/x0vncserver
new file mode 100755 (executable)
index 0000000..d173fe8
Binary files /dev/null and b/linux_usr/x0vncserver differ
index ee8e31c..4360a64 100644 (file)
@@ -129,7 +129,10 @@ struct guest_info {
     v3_core_operating_mode_t core_run_state;
 
     /* the logical cpu on which this core runs */
-    uint32_t cpu_id;
+    uint32_t pcpu_id;
+    
+    /* The virtual core # of this cpu (what the guest sees this core as) */
+    uint32_t vcpu_id;
      
 };
 
index 7f2eb45..5a2856a 100644 (file)
 #include <palacios/vmm_types.h>
 
 
+#include <palacios/vmm_queue.h>
+#include <palacios/vmm_lock.h>
+
+/* The locking in this file is nasty.
+ * There are 3 different locking approaches that are taken, depending on the APIC operation
+ * 1. Queue locks. Actual irq insertions are done via queueing irq ops at the dest apic. 
+ *    The destination apic's core is responsible for draining the queue, and actually 
+ *    setting the vector table. 
+ * 2. State locks. This is a standard lock taken when internal apic state is read/written. 
+ *    When an irq's destination is determined this lock is taken to examine the apic's 
+ *    addressability. 
+ * 3. VM barrier lock. This is taken when actual VM core state is changed (via SIPI). 
+ */
+
 
 
 #ifndef V3_CONFIG_DEBUG_APIC
@@ -225,6 +239,9 @@ struct apic_state {
 
     struct v3_timer * timer;
 
+    v3_lock_t state_lock;
+    struct v3_queue irq_queue;
+
     uint32_t eoi;
 
 
@@ -304,6 +321,9 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
     apic->spec_eoi.val = 0x00000000;
 
 
+    v3_init_queue(&(apic->irq_queue));
+
+
 }
 
 
@@ -312,9 +332,9 @@ static void init_apic_state(struct apic_state * apic, uint32_t id) {
 
 static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
 
-    PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->cpu_id);
+    PrintDebug("apic %u: core %u: MSR read\n", apic->lapic_id.val, core->vcpu_id);
 
     dst->value = apic->base_addr;
 
@@ -324,16 +344,16 @@ static int read_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t * dst, v
 
 static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)priv_data;
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
-    struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->cpu_id, apic->base_addr);
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
+    struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, apic->base_addr);
 
 
-    PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->cpu_id);
+    PrintDebug("apic %u: core %u: MSR write\n", apic->lapic_id.val, core->vcpu_id);
 
     if (old_reg == NULL) {
        // uh oh...
        PrintError("apic %u: core %u: APIC Base address region does not exit...\n",
-                  apic->lapic_id.val, core->cpu_id);
+                  apic->lapic_id.val, core->vcpu_id);
        return -1;
     }
     
@@ -343,11 +363,11 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
 
     apic->base_addr = src.value;
 
-    if (v3_hook_full_mem(core->vm_info, core->cpu_id, apic->base_addr, 
+    if (v3_hook_full_mem(core->vm_info, core->vcpu_id, apic->base_addr, 
                         apic->base_addr + PAGE_SIZE_4KB, 
                         apic_read, apic_write, apic_dev) == -1) {
        PrintError("apic %u: core %u: Could not hook new APIC Base address\n",
-                  apic->lapic_id.val, core->cpu_id);
+                  apic->lapic_id.val, core->vcpu_id);
 
        return -1;
     }
@@ -358,10 +378,6 @@ static int write_apic_msr(struct guest_info * core, uint_t msr, v3_msr_t src, vo
 
 
 // irq_num is the bit offset into a 256 bit buffer...
-// return values
-//    -1 = error
-//     0 = OK, no interrupt needed now
-//     1 = OK, interrupt needed now
 static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
     int major_offset = (irq_num & ~0x00000007) >> 3;
     int minor_offset = irq_num & 0x00000007;
@@ -370,14 +386,14 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
     uint8_t flag = 0x1 << minor_offset;
 
 
-    if (irq_num <= 15 || irq_num>255) {
+    if (irq_num <= 15 || irq_num > 255) {
        PrintError("apic %u: core %d: Attempting to raise an invalid interrupt: %d\n", 
-                  apic->lapic_id.val, apic->core->cpu_id, irq_num);
+                  apic->lapic_id.val, apic->core->vcpu_id, irq_num);
        return -1;
     }
 
 
-    PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->cpu_id, irq_num);
+    PrintDebug("apic %u: core %d: Raising APIC IRQ %d\n", apic->lapic_id.val, apic->core->vcpu_id, irq_num);
 
     if (*req_location & flag) {
        PrintDebug("Interrupt %d  coallescing\n", irq_num);
@@ -389,7 +405,7 @@ static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
        return 1;
     } else {
        PrintDebug("apic %u: core %d: Interrupt  not enabled... %.2x\n", 
-                  apic->lapic_id.val, apic->core->cpu_id,*en_location);
+                  apic->lapic_id.val, apic->core->vcpu_id, *en_location);
     }
 
     return 0;
@@ -540,13 +556,13 @@ static inline int should_deliver_cluster_ipi(struct guest_info * dst_core,
          ((mda & 0x0f) & (dst_apic->log_dst.dst_log_id & 0x0f)) ) {  /*  I am in the set)        */
 
        PrintDebug("apic %u core %u: accepting clustered IRQ (mda 0x%x == log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
+                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
        
        return 1;
     } else {
        PrintDebug("apic %u core %u: rejecting clustered IRQ (mda 0x%x != log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
+                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
        return 0;
     }
@@ -558,7 +574,7 @@ static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
     if (dst_apic->log_dst.dst_log_id & mda) {  // I am in the set 
 
        PrintDebug("apic %u core %u: accepting flat IRQ (mda 0x%x == log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
+                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
 
        return 1;
@@ -566,7 +582,7 @@ static inline int should_deliver_flat_ipi(struct guest_info * dst_core,
   } else {
 
        PrintDebug("apic %u core %u: rejecting flat IRQ (mda 0x%x != log_dst 0x%x)\n",
-                  dst_apic->lapic_id.val, dst_core->cpu_id, mda, 
+                  dst_apic->lapic_id.val, dst_core->vcpu_id, mda, 
                   dst_apic->log_dst.dst_log_id);
        return 0;
   }
@@ -598,7 +614,7 @@ static int should_deliver_ipi(struct guest_info * dst_core,
 
     } else {
        PrintError("apic %u core %u: invalid destination format register value 0x%x for logical mode delivery.\n", 
-                  dst_apic->lapic_id.val, dst_core->cpu_id, dst_apic->dst_fmt.model);
+                  dst_apic->lapic_id.val, dst_core->vcpu_id, dst_apic->dst_fmt.model);
        return -1;
     }
 }
@@ -622,27 +638,17 @@ static int deliver_ipi(struct apic_state * src_apic,
 
            int do_xcall;
 
-           PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->cpu_id); 
+           PrintDebug("delivering IRQ %d to core %u\n", vector, dst_core->vcpu_id); 
 
            do_xcall = activate_apic_irq(dst_apic, vector);
            
-           if (do_xcall < 0) { 
-               PrintError("Failed to activate apic irq!\n");
-               return -1;
-           }
 
-           if (do_xcall && (dst_apic != src_apic)) { 
-               // Assume core # is same as logical processor for now
-               // TODO FIX THIS FIX THIS
-               // THERE SHOULD BE:  guestapicid->virtualapicid map,
-               //                   cpu_id->logical processor map
-               //     host maitains logical proc->phsysical proc
+
+           if (dst_apic != src_apic) { 
                PrintDebug(" non-local core with new interrupt, forcing it to exit now\n"); 
 
 #ifdef V3_CONFIG_MULTITHREAD_OS
-               v3_interrupt_cpu(dst_core->vm_info, dst_core->cpu_id, 0);
-#else
-               V3_ASSERT(0);
+               v3_interrupt_cpu(dst_core->vm_info, dst_core->pcpu_id, 0);
 #endif
            }
 
@@ -650,14 +656,14 @@ static int deliver_ipi(struct apic_state * src_apic,
        }
        case APIC_INIT_DELIVERY: { 
 
-           PrintDebug(" INIT delivery to core %u\n", dst_core->cpu_id);
+           PrintDebug(" INIT delivery to core %u\n", dst_core->vcpu_id);
 
            // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
 
            // Sanity check
            if (dst_apic->ipi_state != INIT_ST) { 
                PrintError(" Warning: core %u is not in INIT state (mode = %d), ignored (assuming this is the deassert)\n",
-                          dst_core->cpu_id, dst_apic->ipi_state);
+                          dst_core->vcpu_id, dst_apic->ipi_state);
                // Only a warning, since INIT INIT SIPI is common
                break;
            }
@@ -680,7 +686,7 @@ static int deliver_ipi(struct apic_state * src_apic,
            // Sanity check
            if (dst_apic->ipi_state != SIPI) { 
                PrintError(" core %u is not in SIPI state (mode = %d), ignored!\n",
-                          dst_core->cpu_id, dst_apic->ipi_state);
+                          dst_core->vcpu_id, dst_apic->ipi_state);
                break;
            }
 
@@ -700,7 +706,7 @@ static int deliver_ipi(struct apic_state * src_apic,
            dst_core->segments.cs.base = vector << 12;
 
            PrintDebug(" SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
-                      vector, dst_core->segments.cs.selector, dst_core->cpu_id);
+                      vector, dst_core->segments.cs.selector, dst_core->vcpu_id);
            // Maybe need to adjust the APIC?
            
            // We transition the target core to SIPI state
@@ -730,14 +736,14 @@ static struct apic_state * find_physical_apic(struct apic_dev_state *apic_dev, s
 {
     int i;
     
-    if (icr->dst >0 && icr->dst < apic_dev->num_apics) { 
+    if ( (icr->dst > 0) && (icr->dst < apic_dev->num_apics) ) { 
        // see if it simply is the core id
        if (apic_dev->apics[icr->dst].lapic_id.val == icr->dst) { 
            return &(apic_dev->apics[icr->dst]);
        }
     }
 
-    for (i=0;i<apic_dev->num_apics;i++) { 
+    for (i = 0; i < apic_dev->num_apics; i++) { 
        if (apic_dev->apics[i].lapic_id.val == icr->dst) { 
            return &(apic_dev->apics[i]);
        }
@@ -769,9 +775,9 @@ static int route_ipi(struct apic_dev_state * apic_dev,
        case APIC_SHORTHAND_NONE:  // no shorthand
            if (icr->dst_mode == APIC_DEST_PHYSICAL) { 
 
-               dest_apic=find_physical_apic(apic_dev,icr);
+               dest_apic = find_physical_apic(apic_dev, icr);
                
-               if (dest_apic==NULL) { 
+               if (dest_apic == NULL) { 
                    PrintError("apic: Attempted send to unregistered apic id=%u\n", icr->dst);
                    return -1;
                }
@@ -783,29 +789,32 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                }
 
 
-               V3_Print("apic: done\n");
-
+               PrintDebug("apic: done\n");
 
            } else if (icr->dst_mode == APIC_DEST_LOGICAL) {
                
-               if (icr->del_mode!=APIC_LOWEST_DELIVERY ) { 
+               if (icr->del_mode != APIC_LOWEST_DELIVERY) { 
+                   int i;
+                   uint8_t mda = icr->dst;
+
                    // logical, but not lowest priority
                    // we immediately trigger
                    // fixed, smi, reserved, nmi, init, sipi, etc
-                   int i;
-                   
-                   uint8_t mda = icr->dst;
+
                    
                    for (i = 0; i < apic_dev->num_apics; i++) { 
+                       int del_flag = 0;
                        
                        dest_apic = &(apic_dev->apics[i]);
                        
-                       int del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
+                       del_flag = should_deliver_ipi(dest_apic->core, dest_apic, mda);
                        
                        if (del_flag == -1) {
+
                            PrintError("apic: Error checking delivery mode\n");
                            return -1;
                        } else if (del_flag == 1) {
+
                            if (deliver_ipi(src_apic, dest_apic, 
                                            icr->vec, icr->del_mode) == -1) {
                                PrintError("apic: Error: Could not deliver IPI\n");
@@ -814,11 +823,12 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                        }
                    }
                } else {  //APIC_LOWEST_DELIVERY
-                   // logical, lowest priority
                    int i;
                    struct apic_state * cur_best_apic = NULL;
                    uint8_t mda = icr->dst;
                   
+                   // logical, lowest priority
+
                    for (i = 0; i < apic_dev->num_apics; i++) { 
                        int del_flag = 0;
 
@@ -832,7 +842,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                            return -1;
                        } else if (del_flag == 1) {
                            // update priority for lowest priority scan
-                           if (!cur_best_apic) {
+                           if (cur_best_apic == 0) {
                                cur_best_apic = dest_apic;  
                            } else if (dest_apic->task_prio.val < cur_best_apic->task_prio.val) {
                                cur_best_apic = dest_apic;
@@ -872,6 +882,7 @@ static int route_ipi(struct apic_dev_state * apic_dev,
                }
            } else if (icr->dst_mode == APIC_DEST_LOGICAL) {  /* logical delivery */
                PrintError("apic: use of logical delivery in self (untested)\n");
+
                if (deliver_ipi(src_apic, src_apic, icr->vec, icr->del_mode) == -1) {
                    PrintError("apic: Could not deliver IPI to self (logical)\n");
                    return -1;
@@ -911,18 +922,18 @@ static int route_ipi(struct apic_dev_state * apic_dev,
 // External function, expected to acquire lock on apic
 static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]);
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]);
     addr_t reg_addr  = guest_addr - apic->base_addr;
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t val = 0;
 
 
     PrintDebug("apic %u: core %u: at %p: Read apic address space (%p)\n",
-              apic->lapic_id.val, core->cpu_id, apic, (void *)guest_addr);
+              apic->lapic_id.val, core->vcpu_id, apic, (void *)guest_addr);
 
     if (msr->apic_enable == 0) {
        PrintError("apic %u: core %u: Read from APIC address space with disabled APIC, apic msr=0x%llx\n",
-                  apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
+                  apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
        return -1;
     }
 
@@ -1135,7 +1146,7 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
 
        default:
            PrintError("apic %u: core %u: Read from Unhandled APIC Register: %x (getting zero)\n", 
-                      apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
+                      apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
            return -1;
     }
 
@@ -1158,12 +1169,12 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
 
     } else {
        PrintError("apic %u: core %u: Invalid apic read length (%d)\n", 
-                  apic->lapic_id.val, core->cpu_id, length);
+                  apic->lapic_id.val, core->vcpu_id, length);
        return -1;
     }
 
     PrintDebug("apic %u: core %u: Read finished (val=%x)\n", 
-              apic->lapic_id.val, core->cpu_id, *(uint32_t *)dst);
+              apic->lapic_id.val, core->vcpu_id, *(uint32_t *)dst);
 
     return length;
 }
@@ -1174,27 +1185,27 @@ static int apic_read(struct guest_info * core, addr_t guest_addr, void * dst, ui
  */
 static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
     addr_t reg_addr  = guest_addr - apic->base_addr;
     struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
     uint32_t op_val = *(uint32_t *)src;
 
     PrintDebug("apic %u: core %u: at %p and priv_data is at %p\n",
-              apic->lapic_id.val, core->cpu_id, apic, priv_data);
+              apic->lapic_id.val, core->vcpu_id, apic, priv_data);
 
     PrintDebug("apic %u: core %u: write to address space (%p) (val=%x)\n", 
-              apic->lapic_id.val, core->cpu_id, (void *)guest_addr, *(uint32_t *)src);
+              apic->lapic_id.val, core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
 
     if (msr->apic_enable == 0) {
        PrintError("apic %u: core %u: Write to APIC address space with disabled APIC, apic msr=0x%llx\n",
-                  apic->lapic_id.val, core->cpu_id, apic->base_addr_msr.value);
+                  apic->lapic_id.val, core->vcpu_id, apic->base_addr_msr.value);
        return -1;
     }
 
 
     if (length != 4) {
        PrintError("apic %u: core %u: Invalid apic write length (%d)\n", 
-                  apic->lapic_id.val, length, core->cpu_id);
+                  apic->lapic_id.val, length, core->vcpu_id);
        return -1;
     }
 
@@ -1230,14 +1241,14 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
        case EXT_APIC_FEATURE_OFFSET:
 
            PrintError("apic %u: core %u: Attempting to write to read only register %p (error)\n", 
-                      apic->lapic_id.val, core->cpu_id, (void *)reg_addr);
+                      apic->lapic_id.val, core->vcpu_id, (void *)reg_addr);
 
            break;
 
            // Data registers
        case APIC_ID_OFFSET:
            //V3_Print("apic %u: core %u: my id is being changed to %u\n", 
-           //       apic->lapic_id.val, core->cpu_id, op_val);
+           //       apic->lapic_id.val, core->vcpu_id, op_val);
 
            apic->lapic_id.val = op_val;
            break;
@@ -1246,7 +1257,7 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            break;
        case LDR_OFFSET:
            PrintDebug("apic %u: core %u: setting log_dst.val to 0x%x\n",
-                      apic->lapic_id.val, core->cpu_id, op_val);
+                      apic->lapic_id.val, core->vcpu_id, op_val);
            apic->log_dst.val = op_val;
            break;
        case DFR_OFFSET:
@@ -1344,18 +1355,19 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
            tmp_icr = apic->int_cmd;
 
            //      V3_Print("apic %u: core %u: sending cmd 0x%llx to apic %u\n", 
-           //       apic->lapic_id.val, core->cpu_id,
+           //       apic->lapic_id.val, core->vcpu_id,
            //       apic->int_cmd.val, apic->int_cmd.dst);
 
            if (route_ipi(apic_dev, apic, &tmp_icr) == -1) { 
                PrintError("IPI Routing failure\n");
                return -1;
            }
+
            break;
        }
        case INT_CMD_HI_OFFSET: {
            apic->int_cmd.hi = op_val;
-           V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->cpu_id,apic->int_cmd.hi);
+           V3_Print("apic %u: core %u: writing command high=0x%x\n", apic->lapic_id.val, core->vcpu_id,apic->int_cmd.hi);
 
            break;
        }
@@ -1364,12 +1376,12 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
        case SEOI_OFFSET:
        default:
            PrintError("apic %u: core %u: Write to Unhandled APIC Register: %x (ignored)\n", 
-                      apic->lapic_id.val, core->cpu_id, (uint32_t)reg_addr);
+                      apic->lapic_id.val, core->vcpu_id, (uint32_t)reg_addr);
 
            return -1;
     }
 
-    PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->cpu_id);
+    PrintDebug("apic %u: core %u: Write finished\n", apic->lapic_id.val, core->vcpu_id);
 
     return length;
 
@@ -1382,11 +1394,14 @@ static int apic_write(struct guest_info * core, addr_t guest_addr, void * src, u
 
 static int apic_intr_pending(struct guest_info * core, void * private_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
+
+    // drain irq QUEUE
+
     int req_irq = get_highest_irr(apic);
     int svc_irq = get_highest_isr(apic);
 
-    //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->cpu_id,req_irq,svc_irq);
+    //    PrintDebug("apic %u: core %u: req_irq=%d, svc_irq=%d\n",apic->lapic_id.val,info->vcpu_id,req_irq,svc_irq);
 
     if ((req_irq >= 0) && 
        (req_irq > svc_irq)) {
@@ -1400,7 +1415,7 @@ static int apic_intr_pending(struct guest_info * core, void * private_data) {
 
 static int apic_get_intr_number(struct guest_info * core, void * private_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
     int req_irq = get_highest_irr(apic);
     int svc_irq = get_highest_isr(apic);
 
@@ -1466,7 +1481,7 @@ int v3_apic_raise_intr(struct v3_vm_info * vm, uint32_t irq, uint32_t dst, void
 
 static int apic_begin_irq(struct guest_info * core, void * private_data, int irq) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(private_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
     int major_offset = (irq & ~0x00000007) >> 3;
     int minor_offset = irq & 0x00000007;
     uint8_t *req_location = apic->int_req_reg + major_offset;
@@ -1481,7 +1496,7 @@ static int apic_begin_irq(struct guest_info * core, void * private_data, int irq
     } else {
        // do nothing... 
        //PrintDebug("apic %u: core %u: begin irq for %d ignored since I don't own it\n",
-       //         apic->lapic_id.val, core->cpu_id, irq);
+       //         apic->lapic_id.val, core->vcpu_id, irq);
     }
 
     return 0;
@@ -1497,7 +1512,7 @@ static void apic_update_time(struct guest_info * core,
                             uint64_t cpu_cycles, uint64_t cpu_freq, 
                             void * priv_data) {
     struct apic_dev_state * apic_dev = (struct apic_dev_state *)(priv_data);
-    struct apic_state * apic = &(apic_dev->apics[core->cpu_id]); 
+    struct apic_state * apic = &(apic_dev->apics[core->vcpu_id]); 
 
     // The 32 bit GCC runtime is a pile of shit
 #ifdef __V3_64BIT__
@@ -1516,7 +1531,7 @@ static void apic_update_time(struct guest_info * core,
     if ((apic->tmr_init_cnt == 0) || 
        ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
          (apic->tmr_cur_cnt == 0))) {
-       //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->cpu_id);
+       //PrintDebug("apic %u: core %u: APIC timer not yet initialized\n",apic->lapic_id.val,info->vcpu_id);
        return;
     }
 
@@ -1548,7 +1563,7 @@ static void apic_update_time(struct guest_info * core,
            break;
        default:
            PrintError("apic %u: core %u: Invalid Timer Divider configuration\n",
-                      apic->lapic_id.val, core->cpu_id);
+                      apic->lapic_id.val, core->vcpu_id);
            return;
     }
 
@@ -1563,18 +1578,18 @@ static void apic_update_time(struct guest_info * core,
 
        // raise irq
        PrintDebug("apic %u: core %u: Raising APIC Timer interrupt (periodic=%d) (icnt=%d) (div=%d)\n",
-                  apic->lapic_id.val, core->cpu_id,
+                  apic->lapic_id.val, core->vcpu_id,
                   apic->tmr_vec_tbl.tmr_mode, apic->tmr_init_cnt, shift_num);
 
        if (apic_intr_pending(core, priv_data)) {
            PrintDebug("apic %u: core %u: Overriding pending IRQ %d\n", 
-                      apic->lapic_id.val, core->cpu_id, 
+                      apic->lapic_id.val, core->vcpu_id, 
                       apic_get_intr_number(core, priv_data));
        }
 
        if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
            PrintError("apic %u: core %u: Could not raise Timer interrupt\n",
-                      apic->lapic_id.val, core->cpu_id);
+                      apic->lapic_id.val, core->vcpu_id);
        }
     
        if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
@@ -1673,7 +1688,7 @@ static int apic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
            return -1;
        }
 
-       v3_hook_full_mem(vm, core->cpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
+       v3_hook_full_mem(vm, core->vcpu_id, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, apic_dev);
 
        PrintDebug("apic %u: (setup device): done, my id is %u\n", i, apic->lapic_id.val);
     }
index 29b7378..6e5687c 100644 (file)
@@ -1194,7 +1194,7 @@ static int vga_write(struct guest_info * core,
 #endif
                    // rotate data right
                    if (ror) { 
-                       data = (data>>ror) | data<<(8-ror);
+                       data = (data>>ror) | (data<<(8-ror));
                    }
                    
 #if DEBUG_DEEP_MEM
@@ -1384,7 +1384,7 @@ static int vga_write(struct guest_info * core,
                uint8_t data = ((uint8_t *)src)[i];
 
                if (ror) {
-                   data = (data>>ror) | data<<(8-ror);
+                   data = (data>>ror) | (data<<(8-ror));
                }
 
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data;
index 7b89a91..5a440c1 100644 (file)
@@ -53,7 +53,7 @@ static int init_inspector_core(struct guest_info * core, void * priv_data) {
     struct v3_inspector_state * vm_state = priv_data;
     char core_name[50];
 
-    snprintf(core_name, 50, "core.%d", core->cpu_id);
+    snprintf(core_name, 50, "core.%d", core->vcpu_id);
 
     {
        struct v3_mtree * core_node = v3_mtree_create_subtree(&(vm_state->state_tree), core_name);
index 665d6be..6fd9931 100644 (file)
@@ -155,7 +155,7 @@ static int init() {
     if (khz) {
        time_state->guest_cpu_freq = atoi(khz);
        PrintDebug("Core %d CPU frequency requested at %d khz.\n", 
-                  info->cpu_id, time_state->guest_cpu_freq);
+                  info->pcpu_id, time_state->guest_cpu_freq);
     } 
     
     if ( (khz == NULL) || 
index 2aae928..fab26fd 100644 (file)
@@ -277,7 +277,7 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * core, addr_t fault
     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->vcpu_id, guest_pa);
 
     if (shdw_reg == NULL) {
        // Inject a machine check in the guest
@@ -459,7 +459,7 @@ static int handle_4MB_shadow_pagefault_pte_32(struct guest_info * core,
     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
index 91a77c6..8a2e094 100644 (file)
@@ -274,7 +274,7 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * core, addr_t fault
     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->vcpu_id, guest_pa);
 
     if (shdw_reg == NULL) {
        // Inject a machine check in the guest
@@ -322,7 +322,7 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * core, addr_t fault
 
        if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
            (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
-           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_pa);
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->vcpu_id, guest_pa);
       
            shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
 
@@ -408,7 +408,7 @@ static int handle_4MB_shadow_pagefault_32(struct guest_info * core,
     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
@@ -431,7 +431,7 @@ static int handle_4MB_shadow_pagefault_32(struct guest_info * core,
 
        if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
            (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
-           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_fault_pa);
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->vcpu_id, guest_fault_pa);
 
            shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
 
index 6ada76b..93a84eb 100644 (file)
@@ -534,7 +534,7 @@ static int handle_pte_shadow_pagefault_64(struct guest_info * core, addr_t fault
 
     PrintDebug("Handling PTE fault\n");
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(core->vm_info, core->vcpu_id, guest_pa);
 
 
 
@@ -607,7 +607,7 @@ pte_noerror:
            int inherited_ar_user = ((inherited_ar & PT_USER_MASK) == PT_USER_MASK) ? 1 : 0;
            int inherited_ar_writable = ((inherited_ar & PT_WRITABLE_MASK) == PT_WRITABLE_MASK) ? 1 : 0;
 
-           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_pa);
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->vcpu_id, guest_pa);
       
            shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
       
@@ -722,7 +722,7 @@ static int handle_2MB_shadow_pagefault_64(struct guest_info * core,
     PrintDebug("Handling 2MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, guest_fault_pa);
 
     int fixed = 0;
     int write_pt = 0;
@@ -743,7 +743,7 @@ static int handle_2MB_shadow_pagefault_64(struct guest_info * core,
 
        if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
            (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
-           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_fault_pa);
+           addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->vcpu_id, guest_fault_pa);
 
            shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
 
index bb5de94..3b745af 100644 (file)
@@ -205,7 +205,7 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault
     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->vcpu_id, guest_pa);
 
     if (shdw_reg == NULL) {
        // Inject a machine check in the guest
@@ -430,7 +430,7 @@ static int handle_4MB_shadow_pagefault_32(struct guest_info * info,
     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
index b4068b2..cb29966 100644 (file)
@@ -408,7 +408,7 @@ static int handle_pte_shadow_pagefault_64(struct guest_info * info, addr_t fault
 
     PrintDebug("Handling PTE fault\n");
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->vcpu_id, guest_pa);
 
 
 
@@ -543,7 +543,7 @@ static int handle_2MB_shadow_pagefault_64(struct guest_info * info,
     PrintDebug("Handling 2MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
index b3f4e43..e638056 100644 (file)
@@ -218,7 +218,7 @@ static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault
     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->vcpu_id, guest_pa);
 
     if (shdw_reg == NULL) {
        // Inject a machine check in the guest
@@ -353,7 +353,7 @@ static int handle_4MB_shadow_pagefault_pte_32(struct guest_info * info,
     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
@@ -448,7 +448,7 @@ static int handle_4MB_shadow_pagefault_pde_32(struct guest_info * info,
     PrintDebug("Handling 4MB fault with large page (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("LargeShadowPDE=%p, LargeGuestPDE=%p\n", large_shadow_pde, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
index 38aebe6..4f31b7f 100644 (file)
@@ -426,7 +426,7 @@ static int handle_pte_shadow_pagefault_64(struct guest_info * info, addr_t fault
 
     PrintDebug("Handling PTE fault\n");
 
-    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->cpu_id, guest_pa);
+    struct v3_mem_region * shdw_reg =  v3_get_mem_region(info->vm_info, info->vcpu_id, guest_pa);
 
 
 
@@ -558,7 +558,7 @@ static int handle_2MB_shadow_pagefault_pde_64(struct guest_info * info,
     PrintDebug("Handling 2MB fault with large page (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("LargeShadowPDE=%p, LargeGuestPDE=%p\n", large_shadow_pde, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
  
     if (shdw_reg == NULL) {
        // Inject a machine check in the guest
@@ -640,7 +640,7 @@ static int handle_2MB_shadow_pagefault_pte_64(struct guest_info * info,
     PrintDebug("Handling 2MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
 
-    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->cpu_id, guest_fault_pa);
+    struct v3_mem_region * shdw_reg = v3_get_mem_region(info->vm_info, info->vcpu_id, guest_fault_pa);
 
  
     if (shdw_reg == NULL) {
index bb5b525..4b5b0a9 100644 (file)
@@ -587,29 +587,31 @@ int v3_start_svm_guest(struct guest_info * info) {
     //    vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
     //  vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
 
-    PrintDebug("Starting SVM core %u\n", info->cpu_id);
+    PrintDebug("Starting SVM core %u (on logical core %u)\n", info->vcpu_id, info->pcpu_id);
 
-    if (info->cpu_id == 0) {
+    if (info->vcpu_id == 0) {
        info->core_run_state = CORE_RUNNING;
        info->vm_info->run_state = VM_RUNNING;
     } else  { 
-       PrintDebug("SVM core %u: Waiting for core initialization\n", info->cpu_id);
+       PrintDebug("SVM core %u (on %u): Waiting for core initialization\n", info->vcpu_id, info->pcpu_id);
 
        while (info->core_run_state == CORE_STOPPED) {
            v3_yield(info);
-           //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id);
+           //PrintDebug("SVM core %u: still waiting for INIT\n", info->vcpu_id);
        }
 
-       PrintDebug("SVM core %u initialized\n", info->cpu_id);
+       PrintDebug("SVM core %u(on %u) initialized\n", info->vcpu_id, info->pcpu_id);
     } 
 
-    PrintDebug("SVM core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
-              info->cpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base), 
+    PrintDebug("SVM core %u(on %u): I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n", 
+              info->vcpu_id, info->pcpu_id, 
+              info->segments.cs.selector, (void *)(info->segments.cs.base), 
               info->segments.cs.limit, (void *)(info->rip));
 
 
 
-    PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
+    PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p) (on cpu %u)\n", 
+              info->vcpu_id, (void *)info->vmm_data, info->pcpu_id);
     //PrintDebugVMCB((vmcb_t*)(info->vmm_data));
     
     v3_start_time(info);
@@ -628,17 +630,17 @@ int v3_start_svm_guest(struct guest_info * info) {
            
            info->vm_info->run_state = VM_ERROR;
            
-           V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id); 
+           V3_Print("SVM core %u: SVM ERROR!!\n", info->vcpu_id); 
            
            v3_print_guest_state(info);
            
-           V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
+           V3_Print("SVM core %u: SVM Exit Code: %p\n", info->vcpu_id, (void *)(addr_t)guest_ctrl->exit_code); 
            
-           V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
-           V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
+           V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
+           V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
            
-           V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
-           V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
+           V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
+           V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
            
            linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
            
@@ -648,9 +650,9 @@ int v3_start_svm_guest(struct guest_info * info) {
                v3_gva_to_hva(info, linear_addr, &host_addr);
            }
            
-           V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
+           V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr);
            
-           V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
+           V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->vcpu_id, (void *)host_addr);
            v3_dump_mem((uint8_t *)host_addr, 15);
            
            v3_print_stack(info);
@@ -665,11 +667,12 @@ int v3_start_svm_guest(struct guest_info * info) {
        }
 
        
-/*
+
        if ((info->num_exits % 5000) == 0) {
            V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
+           v3_print_guest_state(info);
        }
-*/
+
        
     }
 
index ca6c601..8cc497a 100644 (file)
@@ -64,7 +64,7 @@ int v3_hpa_to_hva(addr_t hpa, addr_t * hva) {
 }
 
 int v3_gpa_to_hpa(struct guest_info * info, addr_t gpa, addr_t * hpa) {
-    struct v3_mem_region * reg = v3_get_mem_region(info->vm_info, info->cpu_id, gpa);
+    struct v3_mem_region * reg = v3_get_mem_region(info->vm_info, info->vcpu_id, gpa);
 
     if (reg == NULL) {
        PrintError("In GPA->HPA: Could not find address in shadow map (addr=%p) (NULL REGION)\n", 
index e96bd26..abdeeb6 100644 (file)
@@ -197,8 +197,8 @@ static int start_core(void * p)
     struct guest_info * core = (struct guest_info *)p;
 
 
-    PrintDebug("virtual core %u: in start_core (RIP=%p)\n", 
-              core->cpu_id, (void *)(addr_t)core->rip);
+    PrintDebug("virtual core %u (on logical core %u): in start_core (RIP=%p)\n", 
+              core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
 
     switch (v3_cpu_types[0]) {
 #ifdef V3_CONFIG_SVM
@@ -280,7 +280,6 @@ int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
            i--; // We reset the logical core idx. Not strictly necessary I guess... 
        } else {
 
-           /* This assumes that the core 0 thread has been mapped to physical core 0 */
            if (i == V3_Get_CPU()) {
                // We skip the local CPU because it is reserved for vcore 0
                continue;
@@ -315,6 +314,7 @@ int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
                   core_idx, start_core, core, core->exec_name);
 
        // TODO: actually manage these threads instead of just launching them
+       core->pcpu_id = core_idx;
        core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
 
        if (core_thread == NULL) {
@@ -329,6 +329,8 @@ int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
 
     sprintf(vm->cores[0].exec_name, "%s", vm->name);
 
+    vm->cores[0].pcpu_id = V3_Get_CPU();
+
     if (start_core(&(vm->cores[0])) != 0) {
        PrintError("Error starting VM core 0\n");
        v3_stop_vm(vm);
index bb6f985..8d348e6 100644 (file)
@@ -492,7 +492,7 @@ struct v3_vm_info * v3_config_guest(void * cfg_blob, void * priv_data) {
     for (i = 0; i < vm->num_cores; i++) {
        struct guest_info * info = &(vm->cores[i]);
 
-       info->cpu_id = i;
+       info->vcpu_id = i;
        info->vm_info = vm;
        info->core_cfg_data = per_core_cfg;
 
index e90c3da..ac6f054 100644 (file)
@@ -39,7 +39,7 @@ static inline int handle_passthrough_pagefault_32(struct guest_info * info,
     int pde_index = PDE32_INDEX(fault_addr);
     int pte_index = PTE32_INDEX(fault_addr);
     
-    struct v3_mem_region * region = v3_get_mem_region(info->vm_info, info->cpu_id, fault_addr);
+    struct v3_mem_region * region = v3_get_mem_region(info->vm_info, info->vcpu_id, fault_addr);
 
     if (region == NULL) {
        PrintError("Invalid region in passthrough page fault 32, addr=%p\n", 
index a2bb71d..06e5bb4 100644 (file)
@@ -40,7 +40,7 @@ static inline int handle_passthrough_pagefault_32pae(struct guest_info * info,
     int pde_index = PDE32PAE_INDEX(fault_addr);
     int pte_index = PTE32PAE_INDEX(fault_addr);
 
-    struct v3_mem_region * region =  v3_get_mem_region(info->vm_info, info->cpu_id, fault_addr);
+    struct v3_mem_region * region =  v3_get_mem_region(info->vm_info, info->vcpu_id, fault_addr);
   
     if (region == NULL) {
        PrintError("Invalid region in passthrough page fault 32PAE, addr=%p\n", 
index c428352..217373a 100644 (file)
@@ -42,7 +42,7 @@ static inline int handle_passthrough_pagefault_64(struct guest_info * core, addr
     int pde_index  = PDE64_INDEX(fault_addr);
     int pte_index  = PTE64_INDEX(fault_addr);
 
-    struct v3_mem_region * region =  v3_get_mem_region(core->vm_info, core->cpu_id, fault_addr);
+    struct v3_mem_region * region =  v3_get_mem_region(core->vm_info, core->vcpu_id, fault_addr);
     int page_size = PAGE_SIZE_4KB;
 
     if (region == NULL) {
index 1db9dc6..defad8f 100644 (file)
@@ -144,7 +144,7 @@ int v3_init_core_extensions(struct guest_info * core) {
        if ((ext->impl) && (ext->impl->core_init)) {
            if (ext->impl->core_init(core, ext->priv_data) == -1) {
                PrintError("Error configuring per core extension %s on core %d\n", 
-                          ext->impl->name, core->cpu_id);
+                          ext->impl->name, core->vcpu_id);
                return -1;
            }
        }
index cb5993a..6bb9f5a 100644 (file)
@@ -478,7 +478,7 @@ uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu
                pg_start = PAGE_ADDR_4MB(page_addr);
                pg_end = (pg_start + PAGE_SIZE_4MB);
 
-               reg = get_overlapping_region(core->vm_info, core->cpu_id, pg_start, pg_end); 
+               reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end); 
 
                if ((reg) && ((reg->host_addr % PAGE_SIZE_4MB) == 0)) {
                    page_size = PAGE_SIZE_4MB;
@@ -490,7 +490,7 @@ uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu
                pg_start = PAGE_ADDR_2MB(page_addr);
                pg_end = (pg_start + PAGE_SIZE_2MB);
 
-               reg = get_overlapping_region(core->vm_info, core->cpu_id, pg_start, pg_end);
+               reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
 
                if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
                    page_size = PAGE_SIZE_2MB;
@@ -504,7 +504,7 @@ uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu
                pg_start = PAGE_ADDR_1GB(page_addr);
                pg_end = (pg_start + PAGE_SIZE_1GB);
                
-               reg = get_overlapping_region(core->vm_info, core->cpu_id, pg_start, pg_end);
+               reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
                
                if ((reg) && ((reg->host_addr % PAGE_SIZE_1GB) == 0)) {
                    page_size = PAGE_SIZE_1GB;
@@ -516,7 +516,7 @@ uint32_t v3_get_max_page_size(struct guest_info * core, addr_t page_addr, v3_cpu
                pg_start = PAGE_ADDR_2MB(page_addr);
                pg_end = (pg_start + PAGE_SIZE_2MB);
 
-               reg = get_overlapping_region(core->vm_info, core->cpu_id, pg_start, pg_end);
+               reg = get_overlapping_region(core->vm_info, core->vcpu_id, pg_start, pg_end);
                
                if ((reg) && ((reg->host_addr % PAGE_SIZE_2MB) == 0)) {
                    page_size = PAGE_SIZE_2MB;
index aee8c33..ee632b0 100644 (file)
@@ -169,7 +169,7 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
            src_reg = reg;
        } else {
            // Note that this should only trigger for string operations
-           src_reg = v3_get_mem_region(core->vm_info, core->cpu_id, src_mem_op_gpa);
+           src_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, src_mem_op_gpa);
        }
 
        if (src_reg == NULL) {
@@ -182,7 +182,7 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
        // We don't check whether the region is a hook here because it doesn't yet matter.
        // These hva calculations will be true regardless
        if (src_reg->flags.alloced == 0) {
-           src_mem_op_hva = (addr_t)(hooks->hook_hvas_1 + (PAGE_SIZE * core->cpu_id));
+           src_mem_op_hva = (addr_t)(hooks->hook_hvas_1 + (PAGE_SIZE * core->vcpu_id));
        } else {
            // We already have the region so we can do the conversion ourselves
            src_mem_op_hva = (addr_t)V3_VAddr((void *)((src_mem_op_gpa - src_reg->guest_start) + src_reg->host_addr));
@@ -215,7 +215,7 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
            dst_reg = reg;
        } else {
            // Note that this should only trigger for string operations
-           dst_reg = v3_get_mem_region(core->vm_info, core->cpu_id, dst_mem_op_gpa);
+           dst_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, dst_mem_op_gpa);
        }
 
        if (dst_reg == NULL) {
@@ -228,7 +228,7 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
        // We don't check whether the region is a hook here because it doesn't yet matter.
        // These hva calculations will be true regardless
        if (dst_reg->flags.alloced == 0) {
-           dst_mem_op_hva = (addr_t)(hooks->hook_hvas_2 + (PAGE_SIZE * core->cpu_id));
+           dst_mem_op_hva = (addr_t)(hooks->hook_hvas_2 + (PAGE_SIZE * core->vcpu_id));
        } else {
            // We already have the region so we can do the conversion ourselves
            dst_mem_op_hva = (addr_t)V3_VAddr((void *)((dst_mem_op_gpa - dst_reg->guest_start) + dst_reg->host_addr));
index 7c17c01..caf1a8c 100644 (file)
@@ -56,7 +56,7 @@ static int symspy_msr_write(struct guest_info * core, uint_t msr, struct v3_msr
 
        if (global_state->active == 1) {
            // unmap page
-           struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->cpu_id, 
+           struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id, 
                                                                     (addr_t)global_state->global_guest_pa);
 
            if (old_reg == NULL) {
@@ -84,7 +84,7 @@ static int symspy_msr_write(struct guest_info * core, uint_t msr, struct v3_msr
 
        if (local_state->active == 1) {
            // unmap page
-           struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->cpu_id,
+           struct v3_mem_region * old_reg = v3_get_mem_region(core->vm_info, core->vcpu_id,
                                                                     (addr_t)local_state->local_guest_pa);
 
            if (old_reg == NULL) {
@@ -102,7 +102,7 @@ static int symspy_msr_write(struct guest_info * core, uint_t msr, struct v3_msr
        local_state->active = 1;
 
        // map page
-       v3_add_shadow_mem(core->vm_info, core->cpu_id, (addr_t)local_state->local_guest_pa, 
+       v3_add_shadow_mem(core->vm_info, core->vcpu_id, (addr_t)local_state->local_guest_pa, 
                          (addr_t)(local_state->local_guest_pa + PAGE_SIZE_4KB - 1), 
                          local_state->local_page_pa);
     } else {
@@ -136,7 +136,7 @@ int v3_init_symspy_core(struct guest_info * core, struct v3_symspy_local_state *
     state->local_page = (struct v3_symspy_local_page *)V3_VAddr((void *)state->local_page_pa);
     memset(state->local_page, 0, PAGE_SIZE_4KB);
 
-    snprintf((uint8_t *)&(state->local_page->magic), 8, "V3V.%d", core->cpu_id);
+    snprintf((uint8_t *)&(state->local_page->magic), 8, "V3V.%d", core->vcpu_id);
 
     return 0;
 }
index 09e74b8..42e7822 100644 (file)
@@ -252,7 +252,7 @@ void v3_print_telemetry(struct v3_vm_info * vm) {
        struct exit_event * evt = NULL;
        struct rb_node * node = v3_rb_first(&(core->core_telem.exit_root));
        
-       V3_Print("Exit information for Core %d\n", core->cpu_id);
+       V3_Print("Exit information for Core %d\n", core->vcpu_id);
 
        if (!node) { 
            V3_Print("No information yet for this core\n");
index a0047af..fc2e37e 100644 (file)
@@ -399,8 +399,8 @@ void v3_init_time_core(struct guest_info * info) {
 
     if (khz) {
        time_state->guest_cpu_freq = atoi(khz);
-       PrintDebug("Core %d CPU frequency requested at %d khz.\n", 
-                  info->cpu_id, time_state->guest_cpu_freq);
+       PrintDebug("Logical Core %d (vcpu=%d) CPU frequency requested at %d khz.\n", 
+                  info->pcpu_id, info->vcpu_id, time_state->guest_cpu_freq);
     } 
     
     if ( (khz == NULL) || 
@@ -410,8 +410,8 @@ void v3_init_time_core(struct guest_info * info) {
        time_state->guest_cpu_freq = time_state->host_cpu_freq;
     }
 
-    PrintDebug("Core %d CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n", 
-              info->cpu_id, 
+    PrintDebug("Logical Core %d (vcpu=%d) CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n", 
+              info->pcpu_id, info->vcpu_id,
               time_state->guest_cpu_freq, 
               time_state->host_cpu_freq);
 
index 4a7a6e9..123e23b 100644 (file)
@@ -264,7 +264,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
        v3_vmxassist_init(core, vmx_state);
 
     } else if ((core->shdw_pg_mode == NESTED_PAGING) && 
-              (v3_cpu_types[core->cpu_id] == V3_VMX_EPT_CPU)) {
+              (v3_cpu_types[core->pcpu_id] == V3_VMX_EPT_CPU)) {
 
 #define CR0_PE 0x00000001
 #define CR0_PG 0x80000000
@@ -297,7 +297,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state)
        }
 
     } else if ((core->shdw_pg_mode == NESTED_PAGING) && 
-              (v3_cpu_types[core->cpu_id] == V3_VMX_EPT_UG_CPU)) {
+              (v3_cpu_types[core->pcpu_id] == V3_VMX_EPT_UG_CPU)) {
        int i = 0;
        // For now we will assume that unrestricted guest mode is assured w/ EPT
 
@@ -879,30 +879,30 @@ int v3_vmx_enter(struct guest_info * info) {
 
 int v3_start_vmx_guest(struct guest_info * info) {
 
-    PrintDebug("Starting VMX core %u\n", info->cpu_id);
+    PrintDebug("Starting VMX core %u\n", info->vcpu_id);
 
-    if (info->cpu_id == 0) {
+    if (info->vcpu_id == 0) {
        info->core_run_state = CORE_RUNNING;
        info->vm_info->run_state = VM_RUNNING;
     } else {
 
-        PrintDebug("VMX core %u: Waiting for core initialization\n", info->cpu_id);
+        PrintDebug("VMX core %u: Waiting for core initialization\n", info->vcpu_id);
 
         while (info->core_run_state == CORE_STOPPED) {
             v3_yield(info);
-            //PrintDebug("VMX core %u: still waiting for INIT\n",info->cpu_id);
+            //PrintDebug("VMX core %u: still waiting for INIT\n",info->vcpu_id);
         }
        
-       PrintDebug("VMX core %u initialized\n", info->cpu_id);
+       PrintDebug("VMX core %u initialized\n", info->vcpu_id);
     }
 
 
     PrintDebug("VMX core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x),  RIP=0x%p\n",
-               info->cpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base),
+               info->vcpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base),
                info->segments.cs.limit, (void *)(info->rip));
 
 
-    PrintDebug("VMX core %u: Launching VMX VM\n", info->cpu_id);
+    PrintDebug("VMX core %u: Launching VMX VM on logical core %u\n", info->vcpu_id, info->pcpu_id);
 
     v3_start_time(info);
 
@@ -992,7 +992,7 @@ void v3_init_vmx_cpu(int cpu_id) {
     PrintDebug("VMXON pointer: 0x%p\n", (void *)host_vmcs_ptrs[cpu_id]);
 
     if (vmx_on(host_vmcs_ptrs[cpu_id]) == VMX_SUCCESS) {
-        PrintDebug("VMX Enabled\n");
+        V3_Print("VMX Enabled\n");
     } else {
         PrintError("VMX initialization failure\n");
         return;
index bf1ab86..a66ad6b 100644 (file)
@@ -77,7 +77,7 @@ int v3_handle_ept_fault(struct guest_info * core, addr_t fault_addr, struct ept_
     int pde_index  = PDE64_INDEX(fault_addr);
     int pte_index  = PTE64_INDEX(fault_addr);
 
-    struct v3_mem_region * region = v3_get_mem_region(core->vm_info, core->cpu_id, fault_addr);
+    struct v3_mem_region * region = v3_get_mem_region(core->vm_info, core->vcpu_id, fault_addr);
     int page_size = PAGE_SIZE_4KB;
 
 
index 0433652..2b8f357 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(V3_CONFIG_VNET) +=  vnet_core.o vnet_host.o vnet_hashtable.o
+obj-y += null.o
 
diff --git a/palacios/src/vnet/null.c b/palacios/src/vnet/null.c
new file mode 100644 (file)
index 0000000..1828c44
--- /dev/null
@@ -0,0 +1,6 @@
+/** \file
+ * Do nothing module.
+ *
+ * This file only exists to appease the kbuild gods.
+ */
+