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"
22 #include <linux/vmalloc.h>
26 This is an implementation of the Palacios Graphics Console interface that
27 is designed to interact with a vnc server running in user space,
28 typically something based on x0vncserver.
30 The basic idea is that we manage a frame buffer that we share with
31 palacios. Palacios draws whatever it likes on it.
32 The user-land vncserver will send us requests for fb updates, which
33 we implement by copying the FB to it. When the user-land sends us characters, etc,
34 we deliver those immediately to palacios via the deliver_key and deliver_mouse
35 event interfaces. The end-result is that whatever the graphics system
36 in palacios renders is visible via vnc.
40 static v3_graphics_console_t g_open(void * priv_data,
41 struct v3_frame_buffer_spec *desired_spec,
42 struct v3_frame_buffer_spec *actual_spec)
44 struct v3_guest * guest = (struct v3_guest *)priv_data;
45 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
49 printk("palacios: framebuffer already allocated - returning it\n");
50 *actual_spec=gc->spec;
56 mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
58 printk("palacios: allocating %u bytes for %u by %u by %u buffer\n",
59 mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
61 gc->data = vmalloc(mem);
64 printk("palacios: unable to allocate memory for frame buffer\n");
68 gc->spec = *desired_spec;
70 *actual_spec = gc->spec;
77 printk("palacios: allocated frame buffer\n");
82 static void g_close(v3_graphics_console_t cons)
84 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
89 if (gc->data_refcount<gc->cons_refcount) {
90 printk("palacios: error! data refcount is less than console refcount for graphics console\n");
93 if (gc->cons_refcount>0) {
96 if (gc->cons_refcount<0) {
97 printk("palacios: error! refcount for graphics console is negative on close!\n");
99 if (gc->data_refcount>0) {
100 printk("palacios: error! refcount for graphics console data is positive on close - LEAKING MEMORY\n");
110 static void * g_get_data_read(v3_graphics_console_t cons,
111 struct v3_frame_buffer_spec *cur_spec)
113 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
115 if (gc->data_refcount<=0) {
116 printk("palacios: error! data refcount is <= 0 in get_data_read\n");
126 static void g_release_data_read(v3_graphics_console_t cons)
128 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
132 if (gc->data_refcount<=0) {
133 printk("palacios: error! data refcount is <= zero in release_data_read\n");
138 static void *g_get_data_rw(v3_graphics_console_t cons,
139 struct v3_frame_buffer_spec *cur_spec)
141 return g_get_data_read(cons,cur_spec);
145 static void g_release_data_rw(v3_graphics_console_t cons)
147 return g_release_data_read(cons);
151 static int g_changed(v3_graphics_console_t cons)
153 struct palacios_graphics_console *gc =
154 (struct palacios_graphics_console *) cons;
157 int rc = !(gc->num_updates % 1000);
169 static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
171 struct v3_keyboard_event e;
173 e.scan_code=scancode;
175 v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
180 static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
182 struct v3_mouse_event e;
185 e.data[2]=buttons; // These three are completely wrong, of course - ignoring mouse for now
187 v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
192 static struct v3_graphics_console_hooks palacios_graphics_console_hooks =
197 .get_data_read = g_get_data_read,
198 .release_data_read = g_release_data_read,
199 .get_data_rw = g_get_data_rw,
200 .release_data_rw = g_release_data_rw,
202 .changed = g_changed,
206 int palacios_init_graphics_console( void ) {
208 V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
214 int palacios_graphics_console_user_query(struct palacios_graphics_console *cons,
215 struct v3_fb_query_response __user *u)
217 struct v3_fb_query_response q;
220 if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) {
221 printk("palacios: copy from user in getting query in fb\n");
225 switch (q.request_type) {
227 // returns only the spec for the FB
233 // returns whether an update is available for the region
234 // currently always true
239 case V3_FB_DATA_BOX: {
240 // Not curently implemented
241 printk("palacios: request for data in bounding box unsupported currently\n");
248 case V3_FB_DATA_ALL: {
249 // First let's sanity check to see if they are requesting the same
251 if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) {
252 printk("palacios: request for data with non-matching fb spec \n");
255 // Now let's indicate an update is in the pointer and copy across the data
256 if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) {
257 printk("palacios: unable to copy fb content to user\n");
268 // now we'll copy back any changes we made to the query/response structure
269 if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) {
270 printk("palacios: unable to copy fb response to user\n");
278 int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
279 struct v3_fb_input __user *u)
281 struct v3_fb_input inp;
285 if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) {
286 printk("palacios: copy from user in getting input in fb\n");
290 if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) {
291 rc = palacios_graphics_console_key(cons,inp.scan_code);
294 if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) {
295 rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);