2 * Palacios VM Graphics Console Interface (shared framebuffer between palacios and host)
3 * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.h>
10 #include <linux/uaccess.h>
11 #include <linux/poll.h>
12 #include <linux/anon_inodes.h>
13 #include <linux/file.h>
14 #include <linux/sched.h>
16 #include <interfaces/vmm_console.h>
17 #include <palacios/vmm_host_events.h>
20 #include "palacios-graphics-console.h"
25 This is an implementation of the Palacios Graphics Console interface that
26 is designed to interact with a vnc server running in user space,
27 typically something based on x0vncserver.
29 The basic idea is that we manage a frame buffer that we share with
30 palacios. Palacios draws whatever it likes on it.
31 The user-land vncserver will send us requests for fb updates, which
32 we implement by copying the FB to it. When the user-land sends us characters, etc,
33 we deliver those immediately to palacios via the deliver_key and deliver_mouse
34 event interfaces. The end-result is that whatever the graphics system
35 in palacios renders is visible via vnc.
39 static v3_graphics_console_t g_open(void * priv_data,
40 struct v3_frame_buffer_spec *desired_spec,
41 struct v3_frame_buffer_spec *actual_spec)
43 struct v3_guest * guest = (struct v3_guest *)priv_data;
44 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
48 printk("palacios: framebuffer already allocated - returning it\n");
49 *actual_spec=gc->spec;
55 mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
57 printk("palacios: allocating %u bytes for %u by %u by %u buffer\n",
58 mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
60 gc->data = kmalloc(mem,GFP_KERNEL);
63 printk("palacios: unable to allocate memory for frame buffer\n");
67 gc->spec = *desired_spec;
69 *actual_spec = gc->spec;
76 printk("palacios: allocated frame buffer\n");
81 static void g_close(v3_graphics_console_t cons)
83 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
88 if (gc->data_refcount<gc->cons_refcount) {
89 printk("palacios: error! data refcount is less than console refcount for graphics console\n");
92 if (gc->cons_refcount>0) {
95 if (gc->cons_refcount<0) {
96 printk("palacios: error! refcount for graphics console is negative on close!\n");
98 if (gc->data_refcount>0) {
99 printk("palacios: error! refcount for graphics console data is positive on close - LEAKING MEMORY\n");
109 static void * g_get_data_read(v3_graphics_console_t cons,
110 struct v3_frame_buffer_spec *cur_spec)
112 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
114 if (gc->data_refcount<=0) {
115 printk("palacios: error! data refcount is <= 0 in get_data_read\n");
125 static void g_release_data_read(v3_graphics_console_t cons)
127 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
131 if (gc->data_refcount<=0) {
132 printk("palacios: error! data refcount is <= zero in release_data_read\n");
137 static void *g_get_data_rw(v3_graphics_console_t cons,
138 struct v3_frame_buffer_spec *cur_spec)
140 return g_get_data_read(cons,cur_spec);
144 static void g_release_data_rw(v3_graphics_console_t cons)
146 return g_release_data_read(cons);
150 static int g_changed(v3_graphics_console_t cons)
152 struct palacios_graphics_console *gc =
153 (struct palacios_graphics_console *) cons;
156 int rc = !(gc->num_updates % 1000);
168 static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
170 struct v3_keyboard_event e;
172 e.scan_code=scancode;
174 v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
179 static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
181 struct v3_mouse_event e;
184 e.data[2]=buttons; // These three are completely wrong, of course - ignoring mouse for now
186 v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
191 static struct v3_graphics_console_hooks palacios_graphics_console_hooks =
196 .get_data_read = g_get_data_read,
197 .release_data_read = g_release_data_read,
198 .get_data_rw = g_get_data_rw,
199 .release_data_rw = g_release_data_rw,
201 .changed = g_changed,
205 int palacios_init_graphics_console( void ) {
207 V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
213 int palacios_graphics_console_user_query(struct palacios_graphics_console *cons,
214 struct v3_fb_query_response __user *u)
216 struct v3_fb_query_response q;
219 if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) {
220 printk("palacios: copy from user in getting query in fb\n");
224 switch (q.request_type) {
226 // returns only the spec for the FB
232 // returns whether an update is available for the region
233 // currently always true
238 case V3_FB_DATA_BOX: {
239 // Not curently implemented
240 printk("palacios: request for data in bounding box unsupported currently\n");
247 case V3_FB_DATA_ALL: {
248 // First let's sanity check to see if they are requesting the same
250 if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) {
251 printk("palacios: request for data with non-matching fb spec \n");
254 // Now let's indicate an update is in the pointer and copy across the data
255 if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) {
256 printk("palacios: unable to copy fb content to user\n");
267 // now we'll copy back any changes we made to the query/response structure
268 if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) {
269 printk("palacios: unable to copy fb response to user\n");
277 int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
278 struct v3_fb_input __user *u)
280 struct v3_fb_input inp;
284 if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) {
285 printk("palacios: copy from user in getting input in fb\n");
289 if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) {
290 rc = palacios_graphics_console_key(cons,inp.scan_code);
293 if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) {
294 rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);