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.


9eedbe595a9f700b5710b1f8564dde6d995a5d7e
[palacios.releases.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         printk("Invalid Read operation size: %lu\n", size);
100         return -EFAULT;
101     }
102     
103     msg = dequeue(cons->queue);
104     
105     if (msg == NULL) {
106         printk("ERROR: Null console message\n");
107         return -EFAULT;
108     }
109     
110     if (copy_to_user(buf, msg, size)) {
111         printk("Read Fault\n");
112         return -EFAULT;
113     }
114
115
116     kfree(msg);
117
118     spin_lock_irqsave(&(cons->queue->lock), flags);
119     entries =  cons->queue->num_entries;
120     spin_unlock_irqrestore(&(cons->queue->lock), flags);
121     
122     if (entries > 0) {
123         wake_up_interruptible(&(cons->intr_queue));
124     }
125
126     //    printk("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++, 1)) {
144             printk("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     //    printk("Console=%p (guest=%s)\n", cons, cons->guest->name);
162
163
164     poll_wait(filp, &(cons->intr_queue), poll_tb);
165
166     spin_lock_irqsave(&(cons->queue->lock), flags);
167     entries = cons->queue->num_entries;
168     spin_unlock_irqrestore(&(cons->queue->lock), flags);
169
170     if (entries > 0) {
171         //      printk("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     printk("Releasing the Console File desc\n");
185     
186     spin_lock_irqsave(&(cons->queue->lock), flags);
187     cons->connected = 0;
188     spin_unlock_irqrestore(&(cons->queue->lock), flags);
189
190     while ((msg = dequeue(cons->queue))) {
191         kfree(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         printk("Attempted to connect to unopened console\n");
216         return -1;
217     }
218
219     spin_lock_irqsave(&(cons->lock), flags);
220     if (cons->connected == 0) {
221         cons->connected = 1;
222         acquired = 1;
223     }
224     spin_unlock_irqrestore(&(cons->lock), flags);
225
226     if (acquired == 0) {
227         printk("Console already connected\n");
228         return -1;
229     }
230
231     cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
232
233     if (cons_fd < 0) {
234         printk("Error creating console inode\n");
235         return cons_fd;
236     }
237
238     v3_deliver_console_event(guest->v3_ctx, NULL);
239
240
241     printk("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 = kmalloc(sizeof(struct palacios_console), GFP_KERNEL);
251
252     printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
253
254     if (guest == NULL) {
255         printk("ERROR: Cannot open a console on a NULL guest\n");
256         return NULL;
257     }
258
259     if (cons->open == 1) {
260         printk("Console already open\n");
261         return NULL;
262     }
263
264
265     cons->queue = create_queue(CONSOLE_QUEUE_LEN);
266     spin_lock_init(&(cons->lock));
267     init_waitqueue_head(&(cons->intr_queue));
268
269     cons->guest = guest;
270
271     cons->connected = 0;
272     cons->width = width;
273     cons->height = height;
274     cons->open = 1;
275
276
277     add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
278
279     return cons;
280 }
281
282 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
283     //    printk("Posting Console message\n");
284
285     while (enqueue(cons->queue, msg) == -1) {   
286         wake_up_interruptible(&(cons->intr_queue));
287         schedule();
288     }
289
290     wake_up_interruptible(&(cons->intr_queue));
291
292     return 0;
293 }
294
295
296 static int palacios_tty_cursor_set(void * console, int x, int y) {
297     struct palacios_console * cons = (struct palacios_console *)console;
298     struct cons_msg * msg = NULL;
299
300     if (cons->connected == 0) {
301         return 0;
302     }
303
304     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
305
306     msg->op = CONSOLE_CURS_SET;
307     msg->cursor.x = x;
308     msg->cursor.y = y;
309
310     return post_msg(cons, msg);
311 }
312
313 static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
314     struct palacios_console * cons = (struct palacios_console *) console;
315     struct cons_msg * msg = NULL;
316
317     if (cons->connected == 0) {
318         return 0;
319     }
320
321     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
322
323     msg->op = CONSOLE_CHAR_SET;
324     msg->character.x = x;
325     msg->character.y = y;
326     msg->character.c = c;
327     msg->character.style = style;
328
329     return post_msg(cons, msg);
330 }
331
332 static int palacios_tty_scroll(void * console, int lines) {
333     struct palacios_console * cons = (struct palacios_console *) console;
334     struct cons_msg * msg = NULL;
335
336
337     if (cons->connected == 0) {
338         return 0;
339     }
340
341     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
342
343     msg->op = CONSOLE_SCROLL;
344     msg->scroll.lines = lines;
345
346     return post_msg(cons, msg);
347 }
348
349 static int palacios_set_text_resolution(void * console, int cols, int rows) {
350     struct palacios_console * cons = (struct palacios_console *)console;
351     struct cons_msg * msg = NULL;
352
353     if (cons->connected == 0) {
354         return 0;
355     }
356
357     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
358     
359     msg->op = CONSOLE_RESOLUTION;
360     msg->resolution.cols = cols;
361     msg->resolution.rows = rows;
362
363     return post_msg(cons, msg);
364 }
365
366 static int palacios_tty_update(void * console) {
367     struct palacios_console * cons = (struct palacios_console *) console;
368     struct cons_msg * msg = NULL;
369
370     if (cons->connected == 0) {
371         return 0;
372     }
373
374     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
375
376     msg->op = CONSOLE_UPDATE;
377
378     return post_msg(cons, msg);
379 }
380
381 static void palacios_tty_close(void * console) {
382     struct palacios_console * cons = (struct palacios_console *) console;
383
384     cons->open = 0;
385 }
386
387
388
389 static struct v3_console_hooks palacios_console_hooks = {
390     .open                       = palacios_tty_open,
391     .set_cursor                 = palacios_tty_cursor_set,
392     .set_character              = palacios_tty_character_set,
393     .scroll                     = palacios_tty_scroll,
394     .set_text_resolution        = palacios_set_text_resolution,
395     .update                     = palacios_tty_update,
396     .close                      = palacios_tty_close,
397 };
398
399
400
401
402
403
404 static int console_init( void ) {
405     V3_Init_Console(&palacios_console_hooks);
406     
407     return 0;
408 }
409
410
411
412
413 static struct linux_ext console_ext = {
414     .name = "CONSOLE",
415     .init = console_init,
416     .deinit = NULL,
417     .guest_init = NULL,
418     .guest_deinit = NULL
419 };
420
421
422 register_extension(&console_ext);