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.


Ported graphics console support from monolithic version
Peter Dinda [Thu, 5 May 2011 18:10:36 +0000 (13:10 -0500)]
linux_module/palacios-graphics-console.c [new file with mode: 0644]
linux_module/palacios-graphics-console.h [new file with mode: 0644]

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