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.


Updates to linux module to use linux print macros
[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
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 };
71
72
73 static v3_graphics_console_t g_open(void * priv_data, 
74                                     struct v3_frame_buffer_spec *desired_spec,
75                                     struct v3_frame_buffer_spec *actual_spec)
76 {
77     struct v3_guest * guest = (struct v3_guest *)priv_data;
78     struct palacios_graphics_console * gc = NULL;
79     uint32_t mem;
80
81     if (guest == NULL) {
82         return 0;
83     }
84
85     gc = get_vm_ext_data(guest, "GRAPHICS_CONSOLE_INTERFACE");
86     
87     if (gc == NULL) {
88         ERROR("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n");
89         return 0;
90     }
91
92     if (gc->data != NULL) { 
93         DEBUG("palacios: framebuffer already allocated - returning it\n");
94
95         *actual_spec = gc->spec;
96         gc->cons_refcount++;
97         gc->data_refcount++;
98
99         return gc;
100     }
101
102     mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
103
104     DEBUG("palacios: allocating %u bytes for %u by %u by %u buffer\n",
105            mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
106
107     gc->data = vmalloc(mem);
108
109     if (!(gc->data)) { 
110         ERROR("palacios: unable to allocate memory for frame buffer\n");
111         return 0;
112     }
113
114     gc->spec = *desired_spec;
115
116     *actual_spec = gc->spec;
117
118     
119     gc->cons_refcount++;
120     gc->data_refcount++;
121
122     INFO("palacios: allocated frame buffer\n");
123
124     return gc;
125 }
126
127 static  void g_close(v3_graphics_console_t cons)
128 {
129     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
130
131     gc->cons_refcount--;
132     gc->data_refcount--;
133
134     if (gc->data_refcount < gc->cons_refcount) { 
135         ERROR("palacios: error!   data refcount is less than console refcount for graphics console\n");
136     }
137
138     if (gc->cons_refcount > 0) { 
139         return;
140     } else {
141         if (gc->cons_refcount < 0) { 
142             ERROR("palacios: error!  refcount for graphics console is negative on close!\n");
143         }
144         if (gc->data_refcount > 0) { 
145             ERROR("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
146             return;
147         }
148         if (gc->data) { 
149             kfree(gc->data);
150             gc->data=0;
151         }
152     }
153 }
154
155 static void * g_get_data_read(v3_graphics_console_t cons, 
156                               struct v3_frame_buffer_spec *cur_spec)
157 {
158     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
159     
160     if (gc->data_refcount<=0) { 
161         ERROR("palacios: error!  data refcount is <= 0 in get_data_read\n");
162     }
163
164     gc->data_refcount++;
165     
166     *cur_spec=gc->spec;
167     
168     return gc->data;
169 }
170
171 static void g_release_data_read(v3_graphics_console_t cons)
172 {
173     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
174     
175     gc->data_refcount--;
176
177     if (gc->data_refcount<=0) { 
178         ERROR("palacios: error!  data refcount is <= zero in release_data_read\n");
179     }
180     
181 }
182
183 static void *g_get_data_rw(v3_graphics_console_t cons, 
184                            struct v3_frame_buffer_spec *cur_spec)
185 {
186     return g_get_data_read(cons,cur_spec);
187 }
188
189
190 static void g_release_data_rw(v3_graphics_console_t cons)
191 {
192     return g_release_data_read(cons);
193 }
194
195
196 static int g_changed(v3_graphics_console_t cons)
197 {
198
199     struct palacios_graphics_console *gc = 
200         (struct palacios_graphics_console *) cons;
201     int cr;
202   
203     cr = gc->change_request;
204
205     gc->change_request=0;
206
207     gc->num_updates++;
208     
209     return cr;
210
211 }
212
213
214 static int g_register_render_request(
215                                      v3_graphics_console_t cons,
216                                      int (*render_request)(v3_graphics_console_t,
217                                                            void *),
218                                      void *priv_data)
219 {
220    struct palacios_graphics_console *gc =
221      (struct palacios_graphics_console *) cons;
222    
223    gc->render_data = priv_data;
224    gc->render_request = render_request;
225
226    INFO("palacios: installed rendering callback function for graphics console\n");
227    
228    return 0;
229
230 }
231
232 static int g_register_update_inquire(
233                                      v3_graphics_console_t cons,
234                                      int (*update_inquire)(v3_graphics_console_t,
235                                                            void *),
236                                      void *priv_data)
237 {
238    struct palacios_graphics_console *gc =
239      (struct palacios_graphics_console *) cons;
240    
241    gc->update_data = priv_data;
242    gc->update_inquire = update_inquire;
243
244    INFO("palacios: installed update inquiry callback function for graphics console\n");
245    
246    return 0;
247
248 }
249
250 static int palacios_graphics_console_key(struct v3_guest * guest, 
251                                          struct palacios_graphics_console *cons, 
252                                          uint8_t scancode)
253 {
254     struct v3_keyboard_event e;
255     e.status = 0;
256     e.scan_code = scancode;
257
258     //DEBUG("palacios: start key delivery\n");
259
260     v3_deliver_keyboard_event(guest->v3_ctx, &e);
261
262     //DEBUG("palacios: end key delivery\n");
263     
264     return 0;
265 }
266
267 static int palacios_graphics_console_mouse(struct v3_guest * guest, 
268                                            struct palacios_graphics_console *cons, 
269                                            uint8_t x, uint8_t y, uint8_t buttons)
270 {
271     struct v3_mouse_event e;
272     e.data[0]=x;
273     e.data[1]=y;
274     e.data[2]=buttons;   // These three are completely wrong, of course - ignoring mouse for now
275
276     // mouse delivery is broken, so don't do it.
277     // v3_deliver_mouse_event(guest->v3_ctx,&e);
278
279     return 0;
280 }
281
282 static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
283 {
284     .open  = g_open,
285     .close = g_close,
286
287     .get_data_read = g_get_data_read,
288     .release_data_read = g_release_data_read,
289     .get_data_rw = g_get_data_rw,
290     .release_data_rw = g_release_data_rw,
291
292     .changed = g_changed,
293     .register_render_request = g_register_render_request,
294     .register_update_inquire = g_register_update_inquire,
295 };
296
297
298 static int graphics_console_init( void ) {
299
300     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
301     
302     return 0;
303 }
304
305
306 static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg, 
307                     void * priv_data) {
308     
309     struct palacios_graphics_console * cons = priv_data;
310     struct v3_fb_query_response q;
311     
312     
313     if (copy_from_user(&q, (void __user *) arg, sizeof(struct v3_fb_query_response))) { 
314         ERROR("palacios: copy from user in getting query in fb\n");
315         return -EFAULT;
316     }
317     
318     switch (q.request_type) { 
319         case V3_FB_SPEC:
320             //INFO("palacios: request for db spec from Userland\n");
321             // returns only the spec for the FB
322             q.spec = cons->spec;
323
324             break;
325
326         case V3_FB_UPDATE: 
327             //DEBUG("palacios: test for fb updatei from Userland\n");
328             // returns whether an update is available for the region
329             if (cons->update_inquire) {
330               q.updated = cons->update_inquire(cons,cons->update_data);
331             } else {
332               q.updated = 1;
333             }
334             //DEBUG("palacios: update=%d\n",q.updated);
335
336             // request a render, since a FB_DATA will probably soon come
337             cons->change_request = 1;
338
339             break;
340
341         case V3_FB_DATA_BOX: {
342             // Not curently implemented
343             ERROR("palacios: request for data in bounding box unsupported currently\n");
344             return -EFAULT;
345
346         }
347
348             break;
349             
350         case V3_FB_DATA_ALL: {
351             //DEBUG("palacios: got FrameBuffer Request from Userland\n");
352             // First let's sanity check to see if they are requesting the same
353             // spec that we have
354             if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { 
355                 ERROR("palacios: request for data with non-matching fb spec \n");
356                 return -EFAULT;
357             }
358             // Now we will force a render if we can
359             if (cons->render_request) {
360                  //DEBUG("palacios: making rendering request\n");
361                  cons->render_request(cons,cons->render_data);
362             }
363
364             // Now let's indicate an update is in the pointer and copy across the data
365             if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { 
366                 ERROR("palacios: unable to copy fb content to user\n");
367                 return -EFAULT;
368             }
369             //DEBUG("palacios: FrameBuffer copy out done\n");
370             q.updated = 1;
371             // Now we don't need to request a render
372             cons->change_request = 0;
373         }
374             break;
375             
376         default:
377             return -EFAULT;
378     }
379
380     // now we'll copy back any changes we made to the query/response structure
381     if (copy_to_user((void __user *) arg, (void*)&q, sizeof(struct v3_fb_query_response))) { 
382         ERROR("palacios: unable to copy fb response to user\n");
383         return -EFAULT;
384     }
385
386     return 0;
387
388 }
389
390 static int fb_input(struct v3_guest * guest, 
391                     unsigned int cmd, 
392                     unsigned long arg, 
393                     void * priv_data) {
394
395     struct palacios_graphics_console * cons = priv_data;
396     struct v3_fb_input inp;
397     int rc = 0;
398
399
400     if (copy_from_user(&inp, (void __user *) arg, sizeof(struct v3_fb_input))) { 
401         ERROR("palacios: copy from user in getting input in fb\n");
402         return -EFAULT;
403     }
404
405     //DEBUG("palacios: input from Userland\n");   
406         
407     if ((inp.data_type == V3_FB_KEY) || (inp.data_type == V3_FB_BOTH)) { 
408         rc = palacios_graphics_console_key(guest, cons, inp.scan_code);
409         //DEBUG("palacios: key delivered to palacios\n");
410     }
411
412     if ((inp.data_type == V3_FB_MOUSE) || (inp.data_type == V3_FB_BOTH)) { 
413         rc |= palacios_graphics_console_mouse(guest, cons, inp.mouse_data[0],
414                                               inp.mouse_data[1], inp.mouse_data[2]);
415        //DEBUG("palacios: mouse delivered to palacios\n");
416     }
417
418     if (rc) { 
419         return -EFAULT;
420     } else {
421         cons->change_request=1;
422         return 0;
423     }
424 }
425
426
427 static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) {
428     struct palacios_graphics_console * graphics_cons = kmalloc(sizeof(struct palacios_graphics_console), GFP_KERNEL);
429
430     if (!graphics_cons) { 
431         ERROR("palacios: filed to do guest_init for graphics console\n");
432         return -1;
433     }
434
435     memset(graphics_cons, 0, sizeof(struct palacios_graphics_console));
436
437     *vm_data = graphics_cons;
438
439     add_guest_ctrl(guest, V3_VM_FB_INPUT, fb_input, graphics_cons);
440     add_guest_ctrl(guest, V3_VM_FB_QUERY, fb_query, graphics_cons);
441
442     return 0;
443 }
444
445
446
447 static struct linux_ext graphics_cons_ext = {
448     .name = "GRAPHICS_CONSOLE_INTERFACE",
449     .init = graphics_console_init,
450     .deinit = NULL,
451     .guest_init = graphics_console_guest_init,
452     .guest_deinit = NULL
453 };
454
455
456 register_extension(&graphics_cons_ext);