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.


0b03b62b4ced52d6656c075d3322fc9954aba290
[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
23 /*
24
25   This is an implementation of the Palacios Graphics Console interface that
26   is designed to interact with a vnc server running in user space, 
27   typically something based on x0vncserver.  
28
29   The basic idea is that we manage a frame buffer that we share with
30   palacios.   Palacios draws whatever it likes on it.  
31   The user-land vncserver will send us requests   for fb updates, which
32   we implement by copying the FB to it.   When the user-land sends us characters, etc,
33   we deliver those immediately to palacios via the deliver_key and deliver_mouse
34   event interfaces.  The end-result is that whatever the graphics system
35   in palacios renders is visible via vnc.
36
37 */
38
39 static v3_graphics_console_t g_open(void * priv_data, 
40                                     struct v3_frame_buffer_spec *desired_spec,
41                                     struct v3_frame_buffer_spec *actual_spec)
42 {
43     struct v3_guest * guest = (struct v3_guest *)priv_data;
44     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
45     uint32_t mem;
46
47     if(gc->data) { 
48         printk("palacios: framebuffer already allocated - returning it\n");
49         *actual_spec=gc->spec;
50         gc->cons_refcount++;
51         gc->data_refcount++;
52         return gc;
53     }
54
55     mem = desired_spec->width * desired_spec->height * desired_spec->bytes_per_pixel;
56
57     printk("palacios: allocating %u bytes for %u by %u by %u buffer\n",
58            mem, desired_spec->width, desired_spec->height, desired_spec->bytes_per_pixel);
59
60     gc->data = kmalloc(mem,GFP_KERNEL);
61
62     if (!(gc->data)) { 
63         printk("palacios: unable to allocate memory for frame buffer\n");
64         return 0;
65     }
66
67     gc->spec = *desired_spec;
68
69     *actual_spec = gc->spec;
70
71     gc->guest=guest;
72     
73     gc->cons_refcount++;
74     gc->data_refcount++;
75
76     printk("palacios: allocated frame buffer\n");
77
78     return gc;
79 }
80
81 static  void g_close(v3_graphics_console_t cons)
82 {
83     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
84
85     gc->cons_refcount--;
86     gc->data_refcount--;
87
88     if (gc->data_refcount<gc->cons_refcount) { 
89         printk("palacios: error!   data refcount is less than console refcount for graphics console\n");
90     }
91
92     if (gc->cons_refcount>0) { 
93         return;
94     } else {
95         if (gc->cons_refcount<0) { 
96             printk("palacios: error!  refcount for graphics console is negative on close!\n");
97         }
98         if (gc->data_refcount>0) { 
99             printk("palacios: error!  refcount for graphics console data is positive on close - LEAKING MEMORY\n");
100             return;
101         }
102         if (gc->data) { 
103             kfree(gc->data);
104             gc->data=0;
105         }
106     }
107 }
108
109 static void * g_get_data_read(v3_graphics_console_t cons, 
110                               struct v3_frame_buffer_spec *cur_spec)
111 {
112     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
113     
114     if (gc->data_refcount<=0) { 
115         printk("palacios: error!  data refcount is <= 0 in get_data_read\n");
116     }
117
118     gc->data_refcount++;
119     
120     *cur_spec=gc->spec;
121     
122     return gc->data;
123 }
124
125 static void g_release_data_read(v3_graphics_console_t cons)
126 {
127     struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons;
128     
129     gc->data_refcount--;
130
131     if (gc->data_refcount<=0) { 
132         printk("palacios: error!  data refcount is <= zero in release_data_read\n");
133     }
134     
135 }
136
137 static void *g_get_data_rw(v3_graphics_console_t cons, 
138                            struct v3_frame_buffer_spec *cur_spec)
139 {
140     return g_get_data_read(cons,cur_spec);
141 }
142
143
144 static void g_release_data_rw(v3_graphics_console_t cons)
145 {
146     return g_release_data_read(cons);
147 }
148
149
150 static int g_changed(v3_graphics_console_t cons)
151 {
152     struct palacios_graphics_console *gc = 
153         (struct palacios_graphics_console *) cons;
154
155 #if 0
156     int rc =  !(gc->num_updates % 1000);
157     
158     gc->num_updates++;
159     
160     return rc;
161 #else
162     return 1;
163 #endif
164 }
165
166
167
168 static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
169 {
170     struct v3_keyboard_event e;
171     e.status=0;
172     e.scan_code=scancode;
173
174     v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
175     
176     return 0;
177 }
178
179 static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
180 {
181     struct v3_mouse_event e;
182     e.data[0]=x;
183     e.data[1]=y;
184     e.data[2]=buttons;   // These three are completely wrong, of course - ignoring mouse for now
185
186     v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
187
188     return 0;
189 }
190
191 static struct v3_graphics_console_hooks palacios_graphics_console_hooks = 
192 {
193     .open  = g_open,
194     .close = g_close,
195
196     .get_data_read = g_get_data_read,
197     .release_data_read = g_release_data_read,
198     .get_data_rw = g_get_data_rw,
199     .release_data_rw = g_release_data_rw,
200
201     .changed = g_changed,
202 };
203
204
205 int palacios_init_graphics_console( void ) {
206
207     V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
208     
209     return 0;
210 }
211
212
213 int palacios_graphics_console_user_query(struct palacios_graphics_console *cons, 
214                                          struct v3_fb_query_response __user *u)
215 {
216     struct v3_fb_query_response q;
217     
218     
219     if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) { 
220         printk("palacios: copy from user in getting query in fb\n");
221         return -EFAULT;
222     }
223     
224     switch (q.request_type) { 
225         case V3_FB_SPEC:
226             // returns only the spec for the FB
227             q.spec = cons->spec;
228
229             break;
230
231         case V3_FB_UPDATE: 
232             // returns whether an update is available for the region
233             // currently always true
234             q.updated = 1;
235
236             break;
237
238         case V3_FB_DATA_BOX: {
239             // Not curently implemented
240             printk("palacios: request for data in bounding box unsupported currently\n");
241             return -EFAULT;
242
243         }
244
245             break;
246             
247         case V3_FB_DATA_ALL: {
248             // First let's sanity check to see if they are requesting the same
249             // spec that we have
250             if (memcmp(&(q.spec),&(cons->spec),sizeof(struct v3_frame_buffer_spec))) { 
251                 printk("palacios: request for data with non-matching fb spec \n");
252                 return -EFAULT;
253             }
254             // Now let's indicate an update is in the pointer and copy across the data
255             if (copy_to_user(q.data,cons->data,cons->spec.width*cons->spec.height*cons->spec.bytes_per_pixel)) { 
256                 printk("palacios: unable to copy fb content to user\n");
257                 return -EFAULT;
258             }
259             q.updated=1;
260         }
261             break;
262             
263         default:
264             return -EFAULT;
265     }
266
267     // now we'll copy back any changes we made to the query/response structure
268     if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) { 
269         printk("palacios: unable to copy fb response to user\n");
270         return -EFAULT;
271     }
272
273     return 0;
274
275 }
276
277 int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
278                                          struct v3_fb_input __user  *u)
279 {
280     struct v3_fb_input inp;
281     int rc=0;
282
283
284     if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) { 
285         printk("palacios: copy from user in getting input in fb\n");
286         return -EFAULT;
287     }
288         
289     if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) { 
290         rc = palacios_graphics_console_key(cons,inp.scan_code);
291     }
292
293     if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) { 
294         rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);
295     }
296
297     if (rc) { 
298         return -EFAULT;
299     } else {
300         return 0;
301     }
302 }