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.


Avoid strict-aliasing related issues when compiling with optimization
[palacios.git] / linux_module / iface-console.c
1 /* 
2  * VM Console 
3  * (c) Jack Lange, 2010
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 "vm.h"
20 #include "palacios.h"
21 #include "util-queue.h"
22 #include "linux-exts.h"
23
24 typedef enum { CONSOLE_CURS_SET = 1,
25                CONSOLE_CHAR_SET = 2,
26                CONSOLE_SCROLL = 3,
27                CONSOLE_UPDATE = 4,
28                CONSOLE_RESOLUTION = 5} console_op_t;
29
30
31
32 struct palacios_console {
33     struct gen_queue * queue;
34     spinlock_t lock;
35
36     int open;
37     int connected;
38
39     wait_queue_head_t intr_queue;
40
41     unsigned int width;
42     unsigned int height;
43
44     struct v3_guest * guest;
45 };
46
47
48
49 struct cursor_msg {
50     int x;
51     int y;
52 } __attribute__((packed));
53
54 struct character_msg {
55     int x;
56     int y;
57     char c;
58     unsigned char style;
59 } __attribute__((packed));
60
61 struct scroll_msg {
62     int lines;
63 } __attribute__((packed));
64
65
66 struct resolution_msg {
67     int cols;
68     int rows;
69 } __attribute__((packed));
70
71 struct cons_msg {
72     unsigned char op;
73     union {
74         struct cursor_msg cursor;
75         struct character_msg  character;
76         struct scroll_msg scroll;
77         struct resolution_msg resolution;
78     };
79 } __attribute__((packed)); 
80
81
82 /* This is overkill...*/
83 #define CONSOLE_QUEUE_LEN 8096
84
85
86 static ssize_t 
87 console_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
88     struct palacios_console * cons = filp->private_data;
89     struct cons_msg * msg = NULL;
90     unsigned long flags;
91     int entries = 0;
92
93     if (cons->open == 0) {
94         return 0;
95     }
96
97
98     if (size < sizeof(struct cons_msg)) {
99         ERROR("Invalid Read operation size: %lu\n", size);
100         return -EFAULT;
101     }
102     
103     msg = dequeue(cons->queue);
104     
105     if (msg == NULL) {
106         ERROR("ERROR: Null console message\n");
107         return -EFAULT;
108     }
109     
110     if (copy_to_user(buf, msg, size)) {
111         ERROR("Read Fault\n");
112         return -EFAULT;
113     }
114
115
116     palacios_free(msg);
117
118     palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
119     entries =  cons->queue->num_entries;
120     palacios_spinlock_unlock_irqrestore(&(cons->queue->lock), flags);
121     
122     if (entries > 0) {
123         wake_up_interruptible(&(cons->intr_queue));
124     }
125
126     //    DEBUG("Read from console\n");
127     return size;
128 }
129
130
131 static ssize_t 
132 console_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
133     struct palacios_console * cons = filp->private_data;
134     int i = 0;
135     struct v3_keyboard_event event = {0, 0};
136     
137     if (cons->open == 0) {
138         return 0;
139     }
140
141
142     for (i = 0; i < size; i++) {
143         if (copy_from_user(&(event.scan_code), buf + i, 1)) {
144             ERROR("Console Write fault\n");
145             return -EFAULT;
146         }
147
148         v3_deliver_keyboard_event(cons->guest->v3_ctx, &event);
149     }
150     
151     return size;
152 }
153
154 static unsigned int 
155 console_poll(struct file * filp, struct poll_table_struct * poll_tb) {
156     struct palacios_console * cons = filp->private_data;
157     unsigned int mask = POLLIN | POLLRDNORM;
158     unsigned long flags;
159     int entries = 0;
160
161     //    DEBUG("Console=%p (guest=%s)\n", cons, cons->guest->name);
162
163
164     poll_wait(filp, &(cons->intr_queue), poll_tb);
165
166     palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
167     entries = cons->queue->num_entries;
168     palacios_spinlock_unlock_irqrestore(&(cons->queue->lock), flags);
169
170     if (entries > 0) {
171         //      DEBUG("Returning from POLL\n");
172         return mask;
173     }
174     
175     return 0;
176 }
177
178
179 static int console_release(struct inode * i, struct file * filp) {
180     struct palacios_console * cons = filp->private_data;
181     struct cons_msg * msg = NULL;
182     unsigned long flags;
183
184     DEBUG("Releasing the Console File desc\n");
185     
186     palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
187     cons->connected = 0;
188     palacios_spinlock_unlock_irqrestore(&(cons->queue->lock), flags);
189
190     while ((msg = dequeue(cons->queue))) {
191         palacios_free(msg);
192     }
193
194     return 0;
195 }
196
197
198 static struct file_operations cons_fops = {
199     .read     = console_read,
200     .write    = console_write,
201     .poll     = console_poll,
202     .release  = console_release,
203 };
204
205
206
207 static int console_connect(struct v3_guest * guest, unsigned int cmd, 
208                            unsigned long arg, void * priv_data) {
209     struct palacios_console * cons = priv_data;
210     int cons_fd = 0;
211     unsigned long flags;
212     int acquired = 0;
213
214     if (cons->open == 0) {
215         ERROR("Attempted to connect to unopened console\n");
216         return -1;
217     }
218
219     palacios_spinlock_lock_irqsave(&(cons->lock), flags);
220     if (cons->connected == 0) {
221         cons->connected = 1;
222         acquired = 1;
223     }
224     palacios_spinlock_unlock_irqrestore(&(cons->lock), flags);
225
226     if (acquired == 0) {
227         ERROR("Console already connected\n");
228         return -1;
229     }
230
231     cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, O_RDWR);
232
233     if (cons_fd < 0) {
234         ERROR("Error creating console inode\n");
235         return cons_fd;
236     }
237
238     v3_deliver_console_event(guest->v3_ctx, NULL);
239
240
241     INFO("Console connected\n");
242
243     return cons_fd;
244 }
245
246
247
248 static void * palacios_tty_open(void * private_data, unsigned int width, unsigned int height) {
249     struct v3_guest * guest = (struct v3_guest *)private_data;
250     struct palacios_console * cons = palacios_alloc(sizeof(struct palacios_console));
251
252     if (!cons) { 
253         ERROR("Cannot allocate memory for console\n");
254         return NULL;
255     }
256
257     INFO("Guest initialized virtual console (Guest=%s)\n", guest->name);
258
259     if (guest == NULL) {
260         ERROR("ERROR: Cannot open a console on a NULL guest\n");
261         palacios_free(cons);
262         return NULL;
263     }
264
265     if (cons->open == 1) {
266         ERROR("Console already open\n");
267         palacios_free(cons);
268         return NULL;
269     }
270
271
272     cons->queue = create_queue(CONSOLE_QUEUE_LEN);
273     palacios_spinlock_init(&(cons->lock));
274     init_waitqueue_head(&(cons->intr_queue));
275
276     cons->guest = guest;
277
278     cons->connected = 0;
279     cons->width = width;
280     cons->height = height;
281     cons->open = 1;
282
283
284     add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
285
286     return cons;
287 }
288
289 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
290     //    DEBUG("Posting Console message\n");
291
292     while (enqueue(cons->queue, msg) == -1) {   
293         wake_up_interruptible(&(cons->intr_queue));
294         schedule();
295     }
296
297     wake_up_interruptible(&(cons->intr_queue));
298
299     return 0;
300 }
301
302
303 static int palacios_tty_cursor_set(void * console, int x, int y) {
304     struct palacios_console * cons = (struct palacios_console *)console;
305     struct cons_msg * msg = NULL;
306
307     if (cons->connected == 0) {
308         return 0;
309     }
310
311     msg = palacios_alloc(sizeof(struct cons_msg));
312
313     if (!msg) { 
314         ERROR("Cannot allocate cursor set message in console\n");
315         return -1;
316     }
317
318     msg->op = CONSOLE_CURS_SET;
319     msg->cursor.x = x;
320     msg->cursor.y = y;
321
322     return post_msg(cons, msg);
323 }
324
325 static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
326     struct palacios_console * cons = (struct palacios_console *) console;
327     struct cons_msg * msg = NULL;
328
329     if (cons->connected == 0) {
330         return 0;
331     }
332
333     msg = palacios_alloc(sizeof(struct cons_msg));
334
335     if (!msg) { 
336         ERROR("Cannot allocate character set message in console\n");
337         return -1;
338     }
339
340     msg->op = CONSOLE_CHAR_SET;
341     msg->character.x = x;
342     msg->character.y = y;
343     msg->character.c = c;
344     msg->character.style = style;
345
346     return post_msg(cons, msg);
347 }
348
349 static int palacios_tty_scroll(void * console, int lines) {
350     struct palacios_console * cons = (struct palacios_console *) console;
351     struct cons_msg * msg = NULL;
352
353
354     if (cons->connected == 0) {
355         return 0;
356     }
357
358     msg = palacios_alloc(sizeof(struct cons_msg));
359
360     if (!msg) { 
361         ERROR("Cannot allocate scroll message in console\n");
362         return -1;
363     }
364
365     msg->op = CONSOLE_SCROLL;
366     msg->scroll.lines = lines;
367
368     return post_msg(cons, msg);
369 }
370
371 static int palacios_set_text_resolution(void * console, int cols, int rows) {
372     struct palacios_console * cons = (struct palacios_console *)console;
373     struct cons_msg * msg = NULL;
374
375     if (cons->connected == 0) {
376         return 0;
377     }
378
379     msg = palacios_alloc(sizeof(struct cons_msg));
380
381     if (!msg) { 
382         ERROR("Cannot allocate text resolution message in console\n");
383         return -1;
384     }
385     
386     msg->op = CONSOLE_RESOLUTION;
387     msg->resolution.cols = cols;
388     msg->resolution.rows = rows;
389
390     return post_msg(cons, msg);
391 }
392
393 static int palacios_tty_update(void * console) {
394     struct palacios_console * cons = (struct palacios_console *) console;
395     struct cons_msg * msg = NULL;
396
397     if (cons->connected == 0) {
398         return 0;
399     }
400
401     msg = palacios_alloc(sizeof(struct cons_msg));
402
403     if (!msg) { 
404         ERROR("Cannot allocate update message in console\n");
405         return -1;
406     }
407
408     msg->op = CONSOLE_UPDATE;
409
410     return post_msg(cons, msg);
411 }
412
413 static void palacios_tty_close(void * console) {
414     struct palacios_console * cons = (struct palacios_console *) console;
415
416     cons->open = 0;
417
418     remove_guest_ctrl(cons->guest, V3_VM_CONSOLE_CONNECT);
419     deinit_queue(cons->queue);
420     
421     palacios_spinlock_deinit(&(cons->lock));
422        
423     palacios_free(cons);
424 }
425
426
427
428 static struct v3_console_hooks palacios_console_hooks = {
429     .open                       = palacios_tty_open,
430     .set_cursor                 = palacios_tty_cursor_set,
431     .set_character              = palacios_tty_character_set,
432     .scroll                     = palacios_tty_scroll,
433     .set_text_resolution        = palacios_set_text_resolution,
434     .update                     = palacios_tty_update,
435     .close                      = palacios_tty_close,
436 };
437
438
439
440
441
442
443 static int console_init( void ) {
444     V3_Init_Console(&palacios_console_hooks);
445     
446     return 0;
447 }
448
449 static int console_deinit(void)
450 {
451     // nothing to do
452     return 0;
453 }
454
455
456
457 static struct linux_ext console_ext = {
458     .name = "CONSOLE",
459     .init = console_init,
460     .deinit = console_deinit,
461     .guest_init = NULL,
462     .guest_deinit = NULL
463 };
464
465
466 register_extension(&console_ext);