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.


9e1354673e033c87b7f63c9029cd3c14457ca69b
[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         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 + i, 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
213     if (cons->open == 0) {
214         printk("Attempted to connect to unopened console\n");
215         return -1;
216     }
217
218     spin_lock_irqsave(&(cons->lock), flags);
219
220     cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, O_RDWR);
221
222     if (cons_fd < 0) {
223         printk("Error creating console inode\n");
224         return cons_fd;
225     }
226
227     cons->connected = 1;
228     
229     v3_deliver_console_event(guest->v3_ctx, NULL);
230     spin_unlock_irqrestore(&(cons->lock), flags);
231
232     printk("Console connected\n");
233
234     return cons_fd;
235 }
236
237
238
239 static void * palacios_tty_open(void * private_data, unsigned int width, unsigned int height) {
240     struct v3_guest * guest = (struct v3_guest *)private_data;
241     struct palacios_console * cons = kmalloc(sizeof(struct palacios_console), GFP_KERNEL);
242
243     printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
244
245     if (guest == NULL) {
246         printk("ERROR: Cannot open a console on a NULL guest\n");
247         return NULL;
248     }
249
250     if (cons->open == 1) {
251         printk("Console already open\n");
252         return NULL;
253     }
254
255
256     cons->queue = create_queue(CONSOLE_QUEUE_LEN);
257     spin_lock_init(&(cons->lock));
258     init_waitqueue_head(&(cons->intr_queue));
259
260     cons->guest = guest;
261
262     cons->connected = 0;
263     cons->width = width;
264     cons->height = height;
265     cons->open = 1;
266
267
268     add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
269
270     return cons;
271 }
272
273 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
274     //    printk("Posting Console message\n");
275
276     while (enqueue(cons->queue, msg) == -1) {   
277         wake_up_interruptible(&(cons->intr_queue));
278         schedule();
279     }
280
281     wake_up_interruptible(&(cons->intr_queue));
282
283     return 0;
284 }
285
286
287 static int palacios_tty_cursor_set(void * console, int x, int y) {
288     struct palacios_console * cons = (struct palacios_console *)console;
289     struct cons_msg * msg = NULL;
290
291     if (cons->connected == 0) {
292         return 0;
293     }
294
295     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
296
297     msg->op = CONSOLE_CURS_SET;
298     msg->cursor.x = x;
299     msg->cursor.y = y;
300
301     return post_msg(cons, msg);
302 }
303
304 static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
305     struct palacios_console * cons = (struct palacios_console *) console;
306     struct cons_msg * msg = NULL;
307
308     if (cons->connected == 0) {
309         return 0;
310     }
311
312     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
313
314     msg->op = CONSOLE_CHAR_SET;
315     msg->character.x = x;
316     msg->character.y = y;
317     msg->character.c = c;
318     msg->character.style = style;
319
320     return post_msg(cons, msg);
321 }
322
323 static int palacios_tty_scroll(void * console, int lines) {
324     struct palacios_console * cons = (struct palacios_console *) console;
325     struct cons_msg * msg = NULL;
326
327
328     if (cons->connected == 0) {
329         return 0;
330     }
331
332     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
333
334     msg->op = CONSOLE_SCROLL;
335     msg->scroll.lines = lines;
336
337     return post_msg(cons, msg);
338 }
339
340 static int palacios_set_text_resolution(void * console, int cols, int rows) {
341     struct palacios_console * cons = (struct palacios_console *)console;
342     struct cons_msg * msg = NULL;
343
344     if (cons->connected == 0) {
345         return 0;
346     }
347
348     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
349     
350     msg->op = CONSOLE_RESOLUTION;
351     msg->resolution.cols = cols;
352     msg->resolution.rows = rows;
353
354     return post_msg(cons, msg);
355 }
356
357 static int palacios_tty_update(void * console) {
358     struct palacios_console * cons = (struct palacios_console *) console;
359     struct cons_msg * msg = NULL;
360
361     if (cons->connected == 0) {
362         return 0;
363     }
364
365     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
366
367     msg->op = CONSOLE_UPDATE;
368
369     return post_msg(cons, msg);
370 }
371
372 static void palacios_tty_close(void * console) {
373     struct palacios_console * cons = (struct palacios_console *) console;
374
375     cons->open = 0;
376 }
377
378
379
380 static struct v3_console_hooks palacios_console_hooks = {
381     .open                       = palacios_tty_open,
382     .set_cursor                 = palacios_tty_cursor_set,
383     .set_character              = palacios_tty_character_set,
384     .scroll                     = palacios_tty_scroll,
385     .set_text_resolution        = palacios_set_text_resolution,
386     .update                     = palacios_tty_update,
387     .close                      = palacios_tty_close,
388 };
389
390
391
392
393
394
395 static int console_init( void ) {
396     V3_Init_Console(&palacios_console_hooks);
397     
398     return 0;
399 }
400
401
402
403
404 static struct linux_ext console_ext = {
405     .name = "CONSOLE",
406     .init = console_init,
407     .deinit = NULL,
408     .guest_init = NULL,
409     .guest_deinit = NULL
410 };
411
412
413 register_extension(&console_ext);