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
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 #include "iface-graphics-console.h"
19
20
21 #include "palacios.h"
22 #include "linux-exts.h"
23 #include "vm.h"
24
25
26 /*
27
28   This is an implementation of the Palacios Graphics Console interface that
29   is designed to interact with a vnc server running in user space, 
30   typically something based on x0vncserver.  
31
32   The basic idea is that we manage a frame buffer that we share with
33   palacios.   Palacios draws whatever it likes on it.  
34   The user-land vncserver will send us requests   for fb updates, which
35   we implement by copying the FB to it.   When the user-land sends us characters, etc,
36   we deliver those immediately to palacios via the deliver_key and deliver_mouse
37   event interfaces.  The end-result is that whatever the graphics system
38   in palacios renders is visible via vnc.
39
40 */
41
42
43 static struct list_head global_gcons;
44
45 struct palacios_graphics_console {
46     // descriptor for the data in the shared frame buffer
47     struct v3_frame_buffer_spec spec;
48
49     // the actual shared frame buffer
50     // Note that "shared" here means shared between palacios and us
51     // This data could of course also be shared with userland
52     void * data;
53
54     int cons_refcount;
55     int data_refcount;
56
57     uint32_t num_updates;
58
59     int change_request;
60   
61     int (*render_request)(v3_graphics_console_t cons, 
62                           void *priv_data);
63     void *render_data;
64
65     int (*update_inquire)(v3_graphics_console_t cons,
66                           void *priv_data);
67     
68     void *update_data;
69
70     struct list_head gcons_node;
71
72 };
73
74
75 static v3_graphics_console_t g_open(void * priv_data, 
76                                     struct v3_frame_buffer_spec *desired_spec,
77                                     struct v3_frame_buffer_spec *actual_spec)
78 {
79     struct v3_guest * guest = (struct v3_guest *)priv_data;
80     struct palacios_graphics_console * gc = NULL;
81     uint32_t mem;
82
83     if (guest == NULL) {
84         return 0;
85     }
86
87     gc = get_vm_ext_data(guest, "GRAPHICS_CONSOLE_INTERFACE");
88     
89     if (gc == NULL) {
90         ERROR("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n");
91         return 0;
92     }
93
94     if (gc->data != NULL) { 
95         DEBUG("palacios: framebuffer already allocated - returning it\n");
96
97         *actual_spec = gc->spec;
98         gc->cons_refcount++;
99         gc->data_refcount++;
100
101         return gc;
102     }
103
104     mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
105
106     DEBUG("palacios: allocating %u bytes for %u by %u by %u buffer\n",
107            mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
108
109     gc->data = palacios_valloc(mem);
110
111     if (!(gc->data)) { 
112         ERROR("palacios: unable to allocate memory for frame buffer\n");
113         return 0;
114     }
115
116     gc->spec = *desired_spec;
117
118     *actual_spec = gc->spec;
119
120     
121     gc->cons_refcount++;
122     gc->data_refcount++;
123
124     INFO("palacios: allocated frame buffer\n");
125
126     return gc;
127 }
128
129 static  void g_close(v3_graphics_console_t cons)
130 {
131     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
132
133     gc->cons_refcount--;
134     gc->data_refcount--;
135
136     if (gc->data_refcount < gc->cons_refcount) { 
137         ERROR("palacios: error!   data refcount is less than console refcount for graphics console\n");
138     }
139
140     if (gc->cons_refcount > 0) { 
141         return;
142     } else {
143         if (gc->cons_refcount < 0) { 
144             ERROR("palacios: error!  refcount for graphics console is negative on close!\n");
145         }
146         if (gc->data_refcount > 0) { 
147             ERROR("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
148             return;
149         }
150         if (gc->data) { 
151             palacios_vfree(gc->data);
152             gc->data=0;
153         }
154     }
155 }
156
157 static void * g_get_data_read(v3_graphics_console_t cons, 
158                               struct v3_frame_buffer_spec *cur_spec)
159 {
160     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
161     
162     if (gc->data_refcount<=0) { 
163         ERROR("palacios: error!  data refcount is <= 0 in get_data_read\n");
164     }
165
166     gc->data_refcount++;
167     
168     *cur_spec=gc->spec;
169     
170     return gc->data;
171 }
172
173 static void g_release_data_read(v3_graphics_console_t cons)
174 {
175     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
176     
177     gc->data_refcount--;
178
179     if (gc->data_refcount<=0) { 
180         ERROR("palacios: error!  data refcount is <= zero in release_data_read\n");
181     }
182     
183 }
184
185 static void *g_get_data_rw(v3_graphics_console_t cons, 
186                            struct v3_frame_buffer_spec *cur_spec)
187 {
188     return g_get_data_read(cons,cur_spec);
189 }
190
191
192 static void g_release_data_rw(v3_graphics_console_t cons)
193 {
194     return g_release_data_read(cons);
195 }
196
197
198 static int g_changed(v3_graphics_console_t cons)
199 {
200
201     struct palacios_graphics_console *gc = 
202         (struct palacios_graphics_console *) cons;
203     int cr;
204   
205     cr = gc->change_request;
206
207     gc->change_request=0;
208
209     gc->num_updates++;
210     
211     return cr;
212
213 }
214
215
216 static int g_register_render_request(
217                                      v3_graphics_console_t cons,
218                                      int (*render_request)(v3_graphics_console_t,
219                                                            void *),
220                                      void *priv_data)
221 {
222    struct palacios_graphics_console *gc =
223      (struct palacios_graphics_console *) cons;
224    
225    gc->render_data = priv_data;
226    gc->render_request = render_request;
227
228    INFO("palacios: installed rendering callback function for graphics console\n");
229    
230    return 0;
231
232 }
233
234 static int g_register_update_inquire(
235                                      v3_graphics_console_t cons,
236                                      int (*update_inquire)(v3_graphics_console_t,
237                                                            void *),
238                                      void *priv_data)
239 {
240    struct palacios_graphics_console *gc =
241      (struct palacios_graphics_console *) cons;
242    
243    gc->update_data = priv_data;
244    gc->update_inquire = update_inquire;
245
246    INFO("palacios: installed update inquiry callback function for graphics console\n");
247    
248    return 0;
249
250 }
251
252 static int palacios_graphics_console_key(struct v3_guest * guest, 
253                                          struct palacios_graphics_console *cons, 
254                                          uint8_t scancode)
255 {
256      struct v3_keyboard_event e;
257     e.status = 0;
258     e.scan_code = scancode;
259
260     //DEBUG("palacios: start key delivery\n");
261
262     v3_deliver_keyboard_event(guest->v3_ctx, &e);
263
264     //DEBUG("palacios: end key delivery\n");
265     
266     return 0;
267 }
268
269 static int palacios_graphics_console_mouse(struct v3_guest * guest, 
270                                            struct palacios_graphics_console *cons, 
271                                            uint8_t sx, uint8_t dx,
272                                            uint8_t sy, uint8_t dy,
273                                            uint8_t buttons)
274 {
275
276     struct v3_mouse_event e;
277
278     e.sx=sx;
279     e.dx=dx;
280     e.sy=sy;
281     e.dy=dy;
282     e.buttons=buttons;
283
284     v3_deliver_mouse_event(guest->v3_ctx,&e);
285
286     return 0;
287 }
288
289 static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
290 {
291     .open  = g_open,
292     .close = g_close,
293
294     .get_data_read = g_get_data_read,
295     .release_data_read = g_release_data_read,
296     .get_data_rw = g_get_data_rw,
297     .release_data_rw = g_release_data_rw,
298
299     .changed = g_changed,
300     .register_render_request = g_register_render_request,
301     .register_update_inquire = g_register_update_inquire,
302 };
303
304
305 static int graphics_console_init( void ) {
306
307     INIT_LIST_HEAD(&(global_gcons));
308     
309     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
310     
311     return 0;
312 }
313
314
315 static int graphics_console_deinit( void ) {
316     struct palacios_graphics_console * gc  = NULL;
317     struct palacios_graphics_console * tmp = NULL;
318
319     list_for_each_entry_safe(gc, tmp, &(global_gcons), gcons_node) {
320         list_del(&(gc->gcons_node));
321
322         if (gc->data) 
323             palacios_vfree(gc->data);
324
325         palacios_free(gc);
326     }
327     
328     return 0;
329 }
330
331 static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg, 
332                     void * priv_data) {
333     
334     struct palacios_graphics_console * cons = priv_data;
335     struct v3_fb_query_response q;
336     
337     
338     if (copy_from_user(&q, (void __user *) arg, sizeof(struct v3_fb_query_response))) { 
339         ERROR("palacios: copy from user in getting query in fb\n");
340         return -EFAULT;
341     }
342     
343     switch (q.request_type) { 
344         case V3_FB_SPEC:
345             //INFO("palacios: request for db spec from Userland\n");
346             // returns only the spec for the FB
347             q.spec = cons->spec;
348
349             break;
350
351         case V3_FB_UPDATE: 
352             //DEBUG("palacios: test for fb updatei from Userland\n");
353             // returns whether an update is available for the region
354             if (cons->update_inquire) {
355               q.updated = cons->update_inquire(cons,cons->update_data);
356             } else {
357               q.updated = 1;
358             }
359             //DEBUG("palacios: update=%d\n",q.updated);
360
361             // request a render, since a FB_DATA will probably soon come
362             cons->change_request = 1;
363
364             break;
365
366         case V3_FB_DATA_BOX: {
367             // Not curently implemented
368             ERROR("palacios: request for data in bounding box unsupported currently\n");
369             return -EFAULT;
370
371         }
372
373             break;
374             
375         case V3_FB_DATA_ALL: {
376             //DEBUG("palacios: got FrameBuffer Request from Userland\n");
377             // First let's sanity check to see if they are requesting the same
378             // spec that we have
379             if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { 
380                 ERROR("palacios: request for data with non-matching fb spec \n");
381                 return -EFAULT;
382             }
383             // Now we will force a render if we can
384             if (cons->render_request) {
385                  //DEBUG("palacios: making rendering request\n");
386                  cons->render_request(cons,cons->render_data);
387             }
388
389             // Now let's indicate an update is in the pointer and copy across the data
390             if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { 
391                 ERROR("palacios: unable to copy fb content to user\n");
392                 return -EFAULT;
393             }
394             //DEBUG("palacios: FrameBuffer copy out done\n");
395             q.updated = 1;
396             // Now we don't need to request a render
397             cons->change_request = 0;
398         }
399             break;
400             
401         default:
402             return -EFAULT;
403     }
404
405     // now we'll copy back any changes we made to the query/response structure
406     if (copy_to_user((void __user *) arg, (void*)&q, sizeof(struct v3_fb_query_response))) { 
407         ERROR("palacios: unable to copy fb response to user\n");
408         return -EFAULT;
409     }
410
411     return 0;
412
413 }
414
415 static int fb_input(struct v3_guest * guest, 
416                     unsigned int cmd, 
417                     unsigned long arg, 
418                     void * priv_data) {
419
420     struct palacios_graphics_console * cons = priv_data;
421     struct v3_fb_input inp;
422     int rc = 0;
423
424
425     if (copy_from_user(&inp, (void __user *) arg, sizeof(struct v3_fb_input))) { 
426         ERROR("palacios: copy from user in getting input in fb\n");
427         return -EFAULT;
428     }
429
430     //DEBUG("palacios: input from Userland\n");   
431         
432     if ((inp.data_type == V3_FB_KEY) || (inp.data_type == V3_FB_BOTH)) { 
433         rc = palacios_graphics_console_key(guest, cons, inp.scan_code);
434         //DEBUG("palacios: key delivered to palacios\n");
435     }
436
437     if ((inp.data_type == V3_FB_MOUSE) || (inp.data_type == V3_FB_BOTH)) { 
438         rc |= palacios_graphics_console_mouse(guest, cons, inp.sx, inp.dx, inp.sy, inp.dy, inp.buttons);
439        //DEBUG("palacios: mouse delivered to palacios\n");
440     }
441
442     if (rc) { 
443         return -EFAULT;
444     } else {
445         cons->change_request=1;
446         return 0;
447     }
448 }
449
450
451 static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) {
452     struct palacios_graphics_console * graphics_cons = palacios_alloc(sizeof(struct palacios_graphics_console));
453
454     if (!graphics_cons) { 
455         ERROR("palacios: filed to do guest_init for graphics console\n");
456         return -1;
457     }
458
459     memset(graphics_cons, 0, sizeof(struct palacios_graphics_console));
460
461     *vm_data = graphics_cons;
462
463     add_guest_ctrl(guest, V3_VM_FB_INPUT, fb_input, graphics_cons);
464     add_guest_ctrl(guest, V3_VM_FB_QUERY, fb_query, graphics_cons);
465
466     list_add(&(graphics_cons->gcons_node),&global_gcons);
467
468     return 0;
469 }
470
471
472
473 static int graphics_console_guest_deinit(struct v3_guest * guest, void * vm_data) {
474     struct palacios_graphics_console * graphics_cons = (struct palacios_graphics_console *)vm_data;
475
476     list_del(&(graphics_cons->gcons_node));
477
478     remove_guest_ctrl(guest, V3_VM_FB_INPUT);
479     remove_guest_ctrl(guest, V3_VM_FB_QUERY);
480
481     if (graphics_cons->data) { 
482         palacios_vfree(graphics_cons->data);
483     }
484
485
486     palacios_free(graphics_cons);
487
488     return 0;
489 }
490
491
492 static struct linux_ext graphics_cons_ext = {
493     .name = "GRAPHICS_CONSOLE_INTERFACE",
494     .init = graphics_console_init,
495     .deinit = graphics_console_deinit,
496     .guest_init = graphics_console_guest_init,
497     .guest_deinit = graphics_console_guest_deinit,
498 };
499
500
501 register_extension(&graphics_cons_ext);