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.


bug fixes for extension framework, and porting of console to new interface
[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
154 #if 0
155     struct palacios_graphics_console *gc = 
156         (struct palacios_graphics_console *) cons;
157
158     int rc =  !(gc->num_updates % 1000);
159     
160     gc->num_updates++;
161     
162     return rc;
163 #else
164     return 1;
165 #endif
166 }
167
168
169
170 static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
171 {
172     struct v3_keyboard_event e;
173     e.status=0;
174     e.scan_code=scancode;
175
176     v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
177     
178     return 0;
179 }
180
181 static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
182 {
183     struct v3_mouse_event e;
184     e.data[0]=x;
185     e.data[1]=y;
186     e.data[2]=buttons;   // These three are completely wrong, of course - ignoring mouse for now
187
188     v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
189
190     return 0;
191 }
192
193 static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
194 {
195     .open  = g_open,
196     .close = g_close,
197
198     .get_data_read = g_get_data_read,
199     .release_data_read = g_release_data_read,
200     .get_data_rw = g_get_data_rw,
201     .release_data_rw = g_release_data_rw,
202
203     .changed = g_changed,
204 };
205
206
207 int palacios_init_graphics_console( void ) {
208
209     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
210     
211     return 0;
212 }
213
214
215 int palacios_graphics_console_user_query(struct palacios_graphics_console *cons, 
216                                          struct v3_fb_query_response __user *u)
217 {
218     struct v3_fb_query_response q;
219     
220     
221     if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) { 
222         printk("palacios: copy from user in getting query in fb\n");
223         return -EFAULT;
224     }
225     
226     switch (q.request_type) { 
227         case V3_FB_SPEC:
228             // returns only the spec for the FB
229             q.spec = cons->spec;
230
231             break;
232
233         case V3_FB_UPDATE: 
234             // returns whether an update is available for the region
235             // currently always true
236             q.updated = 1;
237
238             break;
239
240         case V3_FB_DATA_BOX: {
241             // Not curently implemented
242             printk("palacios: request for data in bounding box unsupported currently\n");
243             return -EFAULT;
244
245         }
246
247             break;
248             
249         case V3_FB_DATA_ALL: {
250             // First let's sanity check to see if they are requesting the same
251             // spec that we have
252             if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { 
253                 printk("palacios: request for data with non-matching fb spec \n");
254                 return -EFAULT;
255             }
256             // Now let's indicate an update is in the pointer and copy across the data
257             if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { 
258                 printk("palacios: unable to copy fb content to user\n");
259                 return -EFAULT;
260             }
261             q.updated=1;
262         }
263             break;
264             
265         default:
266             return -EFAULT;
267     }
268
269     // now we'll copy back any changes we made to the query/response structure
270     if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) { 
271         printk("palacios: unable to copy fb response to user\n");
272         return -EFAULT;
273     }
274
275     return 0;
276
277 }
278
279 int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
280                                          struct v3_fb_input __user  *u)
281 {
282     struct v3_fb_input inp;
283     int rc=0;
284
285
286     if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) { 
287         printk("palacios: copy from user in getting input in fb\n");
288         return -EFAULT;
289     }
290         
291     if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) { 
292         rc = palacios_graphics_console_key(cons,inp.scan_code);
293     }
294
295     if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) { 
296         rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);
297     }
298
299     if (rc) { 
300         return -EFAULT;
301     } else {
302         return 0;
303     }
304 }