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...
[palacios.git] / linux_module / palacios-graphics-console.c
1 /*
2  * Palacios VM Graphics Console Interface (shared framebuffer between palacios and host)
3  * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
4  */
5
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.h>
9 #include <linux/fs.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>
15
16 #include <interfaces/vmm_console.h>
17 #include <palacios/vmm_host_events.h>
18
19 #include "palacios.h"
20 #include "palacios-graphics-console.h"
21
22 #include <linux/vmalloc.h>
23
24 /*
25
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.  
29
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.
37
38 */
39
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)
43 {
44     struct v3_guest * guest = (struct v3_guest *)priv_data;
45     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
46     uint32_t mem;
47
48     if(gc->data) { 
49         printk("palacios: framebuffer already allocated - returning it\n");
50         *actual_spec=gc->spec;
51         gc->cons_refcount++;
52         gc->data_refcount++;
53         return gc;
54     }
55
56     mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
57
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);
60
61     gc->data = vmalloc(mem);
62
63     if (!(gc->data)) { 
64         printk("palacios: unable to allocate memory for frame buffer\n");
65         return 0;
66     }
67
68     gc->spec = *desired_spec;
69
70     *actual_spec = gc->spec;
71
72     gc->guest=guest;
73     
74     gc->cons_refcount++;
75     gc->data_refcount++;
76
77     printk("palacios: allocated frame buffer\n");
78
79     return gc;
80 }
81
82 static  void g_close(v3_graphics_console_t cons)
83 {
84     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
85
86     gc->cons_refcount--;
87     gc->data_refcount--;
88
89     if (gc->data_refcount<gc->cons_refcount) { 
90         printk("palacios: error!   data refcount is less than console refcount for graphics console\n");
91     }
92
93     if (gc->cons_refcount>0) { 
94         return;
95     } else {
96         if (gc->cons_refcount<0) { 
97             printk("palacios: error!  refcount for graphics console is negative on close!\n");
98         }
99         if (gc->data_refcount>0) { 
100             printk("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
101             return;
102         }
103         if (gc->data) { 
104             kfree(gc->data);
105             gc->data=0;
106         }
107     }
108 }
109
110 static void * g_get_data_read(v3_graphics_console_t cons, 
111                               struct v3_frame_buffer_spec *cur_spec)
112 {
113     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
114     
115     if (gc->data_refcount<=0) { 
116         printk("palacios: error!  data refcount is <= 0 in get_data_read\n");
117     }
118
119     gc->data_refcount++;
120     
121     *cur_spec=gc->spec;
122     
123     return gc->data;
124 }
125
126 static void g_release_data_read(v3_graphics_console_t cons)
127 {
128     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
129     
130     gc->data_refcount--;
131
132     if (gc->data_refcount<=0) { 
133         printk("palacios: error!  data refcount is <= zero in release_data_read\n");
134     }
135     
136 }
137
138 static void *g_get_data_rw(v3_graphics_console_t cons, 
139                            struct v3_frame_buffer_spec *cur_spec)
140 {
141     return g_get_data_read(cons,cur_spec);
142 }
143
144
145 static void g_release_data_rw(v3_graphics_console_t cons)
146 {
147     return g_release_data_read(cons);
148 }
149
150
151 static int g_changed(v3_graphics_console_t cons)
152 {
153     struct palacios_graphics_console *gc = 
154         (struct palacios_graphics_console *) cons;
155
156 #if 0
157     int rc =  !(gc->num_updates % 1000);
158     
159     gc->num_updates++;
160     
161     return rc;
162 #else
163     return 1;
164 #endif
165 }
166
167
168
169 static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
170 {
171     struct v3_keyboard_event e;
172     e.status=0;
173     e.scan_code=scancode;
174
175     v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
176     
177     return 0;
178 }
179
180 static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
181 {
182     struct v3_mouse_event e;
183     e.data[0]=x;
184     e.data[1]=y;
185     e.data[2]=buttons;   // These three are completely wrong, of course - ignoring mouse for now
186
187     v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
188
189     return 0;
190 }
191
192 static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
193 {
194     .open  = g_open,
195     .close = g_close,
196
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,
201
202     .changed = g_changed,
203 };
204
205
206 int palacios_init_graphics_console( void ) {
207
208     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
209     
210     return 0;
211 }
212
213
214 int palacios_graphics_console_user_query(struct palacios_graphics_console *cons, 
215                                          struct v3_fb_query_response __user *u)
216 {
217     struct v3_fb_query_response q;
218     
219     
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");
222         return -EFAULT;
223     }
224     
225     switch (q.request_type) { 
226         case V3_FB_SPEC:
227             // returns only the spec for the FB
228             q.spec = cons->spec;
229
230             break;
231
232         case V3_FB_UPDATE: 
233             // returns whether an update is available for the region
234             // currently always true
235             q.updated = 1;
236
237             break;
238
239         case V3_FB_DATA_BOX: {
240             // Not curently implemented
241             printk("palacios: request for data in bounding box unsupported currently\n");
242             return -EFAULT;
243
244         }
245
246             break;
247             
248         case V3_FB_DATA_ALL: {
249             // First let's sanity check to see if they are requesting the same
250             // spec that we have
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");
253                 return -EFAULT;
254             }
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");
258                 return -EFAULT;
259             }
260             q.updated=1;
261         }
262             break;
263             
264         default:
265             return -EFAULT;
266     }
267
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");
271         return -EFAULT;
272     }
273
274     return 0;
275
276 }
277
278 int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
279                                          struct v3_fb_input __user  *u)
280 {
281     struct v3_fb_input inp;
282     int rc=0;
283
284
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");
287         return -EFAULT;
288     }
289         
290     if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) { 
291         rc = palacios_graphics_console_key(cons,inp.scan_code);
292     }
293
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]);
296     }
297
298     if (rc) { 
299         return -EFAULT;
300     } else {
301         return 0;
302     }
303 }