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.


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