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.


Cleanup of linkage issues for non-Linux hosts
[palacios.git] / linux_module / iface-graphics-console.c
index 227e90e..6744cfd 100644 (file)
@@ -22,7 +22,6 @@
 #include "linux-exts.h"
 #include "vm.h"
 
-#include <linux/vmalloc.h>
 
 /*
 
@@ -41,6 +40,7 @@
 */
 
 
+static struct list_head global_gcons;
 
 struct palacios_graphics_console {
     // descriptor for the data in the shared frame buffer
@@ -56,10 +56,19 @@ struct palacios_graphics_console {
 
     uint32_t num_updates;
 
-    // Currently keystrokes and mouse movements are ignored
+    int change_request;
+  
+    int (*render_request)(v3_graphics_console_t cons, 
+                          void *priv_data);
+    void *render_data;
+
+    int (*update_inquire)(v3_graphics_console_t cons,
+                         void *priv_data);
+    
+    void *update_data;
+
+    struct list_head gcons_node;
 
-    // currently, we will not worry about locking this
-    // lock_t ...
 };
 
 
@@ -78,12 +87,12 @@ static v3_graphics_console_t g_open(void * priv_data,
     gc = get_vm_ext_data(guest, "GRAPHICS_CONSOLE_INTERFACE");
     
     if (gc == NULL) {
-       printk("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n");
+       ERROR("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n");
        return 0;
     }
 
     if (gc->data != NULL) { 
-       printk("palacios: framebuffer already allocated - returning it\n");
+       DEBUG("palacios: framebuffer already allocated - returning it\n");
 
        *actual_spec = gc->spec;
        gc->cons_refcount++;
@@ -94,13 +103,13 @@ static v3_graphics_console_t g_open(void * priv_data,
 
     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",
+    DEBUG("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 = vmalloc(mem);
+    gc->data = palacios_valloc(mem);
 
     if (!(gc->data)) { 
-       printk("palacios: unable to allocate memory for frame buffer\n");
+       ERROR("palacios: unable to allocate memory for frame buffer\n");
        return 0;
     }
 
@@ -112,7 +121,7 @@ static v3_graphics_console_t g_open(void * priv_data,
     gc->cons_refcount++;
     gc->data_refcount++;
 
-    printk("palacios: allocated frame buffer\n");
+    INFO("palacios: allocated frame buffer\n");
 
     return gc;
 }
@@ -125,21 +134,21 @@ static  void g_close(v3_graphics_console_t cons)
     gc->data_refcount--;
 
     if (gc->data_refcount < gc->cons_refcount) { 
-       printk("palacios: error!   data refcount is less than console refcount for graphics console\n");
+       ERROR("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");
+           ERROR("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");
+           ERROR("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
            return;
        }
        if (gc->data) { 
-           kfree(gc->data);
+           palacios_vfree(gc->data);
            gc->data=0;
        }
     }
@@ -151,7 +160,7 @@ static void * g_get_data_read(v3_graphics_console_t cons,
     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");
+       ERROR("palacios: error!  data refcount is <= 0 in get_data_read\n");
     }
 
     gc->data_refcount++;
@@ -168,7 +177,7 @@ static void g_release_data_read(v3_graphics_console_t cons)
     gc->data_refcount--;
 
     if (gc->data_refcount<=0) { 
-       printk("palacios: error!  data refcount is <= zero in release_data_read\n");
+       ERROR("palacios: error!  data refcount is <= zero in release_data_read\n");
     }
     
 }
@@ -189,43 +198,88 @@ static void g_release_data_rw(v3_graphics_console_t cons)
 static int g_changed(v3_graphics_console_t cons)
 {
 
-#if 0
     struct palacios_graphics_console *gc = 
        (struct palacios_graphics_console *) cons;
+    int cr;
+  
+    cr = gc->change_request;
+
+    gc->change_request=0;
 
-    int rc =  !(gc->num_updates % 1000);
-    
     gc->num_updates++;
     
-    return rc;
-#else
-    return 1;
-#endif
+    return cr;
+
 }
 
 
+static int g_register_render_request(
+                                    v3_graphics_console_t cons,
+                                    int (*render_request)(v3_graphics_console_t,
+                                                          void *),
+                                    void *priv_data)
+{
+   struct palacios_graphics_console *gc =
+     (struct palacios_graphics_console *) cons;
+   
+   gc->render_data = priv_data;
+   gc->render_request = render_request;
+
+   INFO("palacios: installed rendering callback function for graphics console\n");
+   
+   return 0;
+
+}
+
+static int g_register_update_inquire(
+                                    v3_graphics_console_t cons,
+                                    int (*update_inquire)(v3_graphics_console_t,
+                                                          void *),
+                                    void *priv_data)
+{
+   struct palacios_graphics_console *gc =
+     (struct palacios_graphics_console *) cons;
+   
+   gc->update_data = priv_data;
+   gc->update_inquire = update_inquire;
+
+   INFO("palacios: installed update inquiry callback function for graphics console\n");
+   
+   return 0;
+
+}
 
 static int palacios_graphics_console_key(struct v3_guest * guest, 
                                         struct palacios_graphics_console *cons, 
                                         uint8_t scancode)
 {
-    struct v3_keyboard_event e;
+     struct v3_keyboard_event e;
     e.status = 0;
     e.scan_code = scancode;
 
+    //DEBUG("palacios: start key delivery\n");
+
     v3_deliver_keyboard_event(guest->v3_ctx, &e);
+
+    //DEBUG("palacios: end key delivery\n");
     
     return 0;
 }
 
 static int palacios_graphics_console_mouse(struct v3_guest * guest, 
                                           struct palacios_graphics_console *cons, 
-                                          uint8_t x, uint8_t y, uint8_t buttons)
+                                          uint8_t sx, uint8_t dx,
+                                          uint8_t sy, uint8_t dy,
+                                          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
+
+    e.sx=sx;
+    e.dx=dx;
+    e.sy=sy;
+    e.dy=dy;
+    e.buttons=buttons;
 
     v3_deliver_mouse_event(guest->v3_ctx,&e);
 
@@ -243,17 +297,37 @@ static struct v3_graphics_console_hooks palacios_graphics_console_hooks =
     .release_data_rw = g_release_data_rw,
 
     .changed = g_changed,
+    .register_render_request = g_register_render_request,
+    .register_update_inquire = g_register_update_inquire,
 };
 
 
 static int graphics_console_init( void ) {
 
+    INIT_LIST_HEAD(&(global_gcons));
+    
     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
     
     return 0;
 }
 
 
+static int graphics_console_deinit( void ) {
+    struct palacios_graphics_console * gc  = NULL;
+    struct palacios_graphics_console * tmp = NULL;
+
+    list_for_each_entry_safe(gc, tmp, &(global_gcons), gcons_node) {
+        list_del(&(gc->gcons_node));
+
+        if (gc->data) 
+            palacios_vfree(gc->data);
+
+        palacios_free(gc);
+    }
+    
+    return 0;
+}
+
 static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg, 
                    void * priv_data) {
     
@@ -262,27 +336,36 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg
     
     
     if (copy_from_user(&q, (void __user *) arg, sizeof(struct v3_fb_query_response))) { 
-       printk("palacios: copy from user in getting query in fb\n");
+       ERROR("palacios: copy from user in getting query in fb\n");
        return -EFAULT;
     }
     
     switch (q.request_type) { 
        case V3_FB_SPEC:
+           //INFO("palacios: request for db spec from Userland\n");
            // returns only the spec for the FB
            q.spec = cons->spec;
 
            break;
 
        case V3_FB_UPDATE: 
+           //DEBUG("palacios: test for fb updatei from Userland\n");
            // returns whether an update is available for the region
-           // currently always true
-           q.updated = 1;
+           if (cons->update_inquire) {
+             q.updated = cons->update_inquire(cons,cons->update_data);
+           } else {
+             q.updated = 1;
+           }
+            //DEBUG("palacios: update=%d\n",q.updated);
+
+            // request a render, since a FB_DATA will probably soon come
+            cons->change_request = 1;
 
            break;
 
        case V3_FB_DATA_BOX: {
            // Not curently implemented
-           printk("palacios: request for data in bounding box unsupported currently\n");
+           ERROR("palacios: request for data in bounding box unsupported currently\n");
            return -EFAULT;
 
        }
@@ -290,18 +373,28 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg
            break;
            
        case V3_FB_DATA_ALL: {
+            //DEBUG("palacios: got FrameBuffer Request from Userland\n");
            // 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");
+               ERROR("palacios: request for data with non-matching fb spec \n");
                return -EFAULT;
            }
+            // Now we will force a render if we can
+            if (cons->render_request) {
+                //DEBUG("palacios: making rendering request\n");
+                 cons->render_request(cons,cons->render_data);
+            }
+
            // 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");
+               ERROR("palacios: unable to copy fb content to user\n");
                return -EFAULT;
            }
+            //DEBUG("palacios: FrameBuffer copy out done\n");
            q.updated = 1;
+            // Now we don't need to request a render
+            cons->change_request = 0;
        }
            break;
            
@@ -311,7 +404,7 @@ static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg
 
     // now we'll copy back any changes we made to the query/response structure
     if (copy_to_user((void __user *) arg, (void*)&q, sizeof(struct v3_fb_query_response))) { 
-       printk("palacios: unable to copy fb response to user\n");
+       ERROR("palacios: unable to copy fb response to user\n");
        return -EFAULT;
     }
 
@@ -330,32 +423,36 @@ static int fb_input(struct v3_guest * guest,
 
 
     if (copy_from_user(&inp, (void __user *) arg, sizeof(struct v3_fb_input))) { 
-       printk("palacios: copy from user in getting input in fb\n");
+       ERROR("palacios: copy from user in getting input in fb\n");
        return -EFAULT;
     }
+
+    //DEBUG("palacios: input from Userland\n");   
        
     if ((inp.data_type == V3_FB_KEY) || (inp.data_type == V3_FB_BOTH)) { 
        rc = palacios_graphics_console_key(guest, cons, inp.scan_code);
+        //DEBUG("palacios: key delivered to palacios\n");
     }
 
     if ((inp.data_type == V3_FB_MOUSE) || (inp.data_type == V3_FB_BOTH)) { 
-       rc |= palacios_graphics_console_mouse(guest, cons, inp.mouse_data[0],
-                                             inp.mouse_data[1], inp.mouse_data[2]);
+       rc |= palacios_graphics_console_mouse(guest, cons, inp.sx, inp.dx, inp.sy, inp.dy, inp.buttons);
+       //DEBUG("palacios: mouse delivered to palacios\n");
     }
 
     if (rc) { 
        return -EFAULT;
     } else {
+        cons->change_request=1;
        return 0;
     }
 }
 
 
 static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) {
-    struct palacios_graphics_console * graphics_cons = kmalloc(sizeof(struct palacios_graphics_console), GFP_KERNEL);
+    struct palacios_graphics_console * graphics_cons = palacios_alloc(sizeof(struct palacios_graphics_console));
 
     if (!graphics_cons) { 
-       printk("palacios: filed to do guest_init for graphics console\n");
+       ERROR("palacios: filed to do guest_init for graphics console\n");
        return -1;
     }
 
@@ -366,17 +463,38 @@ static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data)
     add_guest_ctrl(guest, V3_VM_FB_INPUT, fb_input, graphics_cons);
     add_guest_ctrl(guest, V3_VM_FB_QUERY, fb_query, graphics_cons);
 
+    list_add(&(graphics_cons->gcons_node),&global_gcons);
+
     return 0;
 }
 
 
 
+static int graphics_console_guest_deinit(struct v3_guest * guest, void * vm_data) {
+    struct palacios_graphics_console * graphics_cons = (struct palacios_graphics_console *)vm_data;
+
+    list_del(&(graphics_cons->gcons_node));
+
+    remove_guest_ctrl(guest, V3_VM_FB_INPUT);
+    remove_guest_ctrl(guest, V3_VM_FB_QUERY);
+
+    if (graphics_cons->data) { 
+       palacios_vfree(graphics_cons->data);
+    }
+
+
+    palacios_free(graphics_cons);
+
+    return 0;
+}
+
+
 static struct linux_ext graphics_cons_ext = {
     .name = "GRAPHICS_CONSOLE_INTERFACE",
     .init = graphics_console_init,
-    .deinit = NULL,
+    .deinit = graphics_console_deinit,
     .guest_init = graphics_console_guest_init,
-    .guest_deinit = NULL
+    .guest_deinit = graphics_console_guest_deinit,
 };