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.


update linux module to support multicore
[palacios.git] / linux_module / palacios-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 "palacios.h"
20 #include "palacios-console.h"
21 #include "palacios-queue.h"
22
23 typedef enum { CONSOLE_CURS_SET = 1,
24                CONSOLE_CHAR_SET = 2,
25                CONSOLE_SCROLL = 3,
26                CONSOLE_UPDATE = 4,
27                CONSOLE_RESOLUTION = 5} console_op_t;
28
29
30
31 struct cursor_msg {
32     int x;
33     int y;
34 } __attribute__((packed));
35
36 struct character_msg {
37     int x;
38     int y;
39     char c;
40     unsigned char style;
41 } __attribute__((packed));
42
43 struct scroll_msg {
44     int lines;
45 } __attribute__((packed));
46
47
48 struct resolution_msg {
49     int cols;
50     int rows;
51 } __attribute__((packed));
52
53 struct cons_msg {
54     unsigned char op;
55     union {
56         struct cursor_msg cursor;
57         struct character_msg  character;
58         struct scroll_msg scroll;
59         struct resolution_msg resolution;
60     };
61 } __attribute__((packed)); 
62
63
64 /* This is overkill...*/
65 #define CONSOLE_QUEUE_LEN 8096
66
67
68 static ssize_t 
69 console_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
70     struct palacios_console * cons = filp->private_data;
71     struct cons_msg * msg = NULL;
72     unsigned long flags;
73     int entries = 0;
74
75     if (cons->open == 0) {
76         return 0;
77     }
78
79
80     if (size < sizeof(struct cons_msg)) {
81         printk("Invalid Read operation size: %lu\n", size);
82         return -EFAULT;
83     }
84     
85     msg = dequeue(cons->queue);
86     
87     if (msg == NULL) {
88         printk("ERROR: Null console message\n");
89         return -EFAULT;
90     }
91     
92     if (copy_to_user(buf, msg, size)) {
93         printk("Read Fault\n");
94         return -EFAULT;
95     }
96
97
98     kfree(msg);
99
100     spin_lock_irqsave(&(cons->queue->lock), flags);
101     entries =  cons->queue->num_entries;
102     spin_unlock_irqrestore(&(cons->queue->lock), flags);
103     
104     if (entries > 0) {
105         wake_up_interruptible(&(cons->intr_queue));
106     }
107
108     //    printk("Read from console\n");
109     return size;
110 }
111
112
113 static ssize_t 
114 console_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
115     struct palacios_console * cons = filp->private_data;
116     int i = 0;
117     struct v3_keyboard_event event = {0, 0};
118     
119     if (cons->open == 0) {
120         return 0;
121     }
122
123
124     for (i = 0; i < size; i++) {
125         if (copy_from_user(&(event.scan_code), buf, 1)) {
126             printk("Console Write fault\n");
127             return -EFAULT;
128         }
129
130         v3_deliver_keyboard_event(cons->guest->v3_ctx, &event);
131     }
132     
133     return size;
134 }
135
136 static unsigned int 
137 console_poll(struct file * filp, struct poll_table_struct * poll_tb) {
138     struct palacios_console * cons = filp->private_data;
139     unsigned int mask = POLLIN | POLLRDNORM;
140     unsigned long flags;
141     int entries = 0;
142
143     //    printk("Console=%p (guest=%s)\n", cons, cons->guest->name);
144
145
146     poll_wait(filp, &(cons->intr_queue), poll_tb);
147
148     spin_lock_irqsave(&(cons->queue->lock), flags);
149     entries = cons->queue->num_entries;
150     spin_unlock_irqrestore(&(cons->queue->lock), flags);
151
152     if (entries > 0) {
153         //      printk("Returning from POLL\n");
154         return mask;
155     }
156     
157     return 0;
158 }
159
160
161 static int console_release(struct inode * i, struct file * filp) {
162     struct palacios_console * cons = filp->private_data;
163     struct cons_msg * msg = NULL;
164     unsigned long flags;
165
166     printk("Releasing the Console File desc\n");
167     
168     spin_lock_irqsave(&(cons->queue->lock), flags);
169     cons->connected = 0;
170     spin_unlock_irqrestore(&(cons->queue->lock), flags);
171
172     while ((msg = dequeue(cons->queue))) {
173         kfree(msg);
174     }
175
176     return 0;
177 }
178
179
180 static struct file_operations cons_fops = {
181     .read     = console_read,
182     .write    = console_write,
183     .poll     = console_poll,
184     .release  = console_release,
185 };
186
187
188
189 int connect_console(struct v3_guest * guest) {
190     struct palacios_console * cons = &(guest->console);
191     int cons_fd = 0;
192     unsigned long flags;
193
194     if (cons->open == 0) {
195         printk("Attempted to connect to unopened console\n");
196         return -1;
197     }
198
199     spin_lock_irqsave(&(cons->lock), flags);
200
201     cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
202
203     if (cons_fd < 0) {
204         printk("Error creating console inode\n");
205         return cons_fd;
206     }
207
208     cons->connected = 1;
209     
210     v3_deliver_console_event(guest->v3_ctx, NULL);
211     spin_unlock_irqrestore(&(cons->lock), flags);
212
213     printk("Console connected\n");
214
215     return cons_fd;
216 }
217
218
219
220 static void * palacios_tty_open(void * private_data, unsigned int width, unsigned int height) {
221     struct v3_guest * guest = (struct v3_guest *)private_data;
222     struct palacios_console * cons = &(guest->console);
223
224     printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
225
226     if (guest == NULL) {
227         printk("ERROR: Cannot open a console on a NULL guest\n");
228         return NULL;
229     }
230
231     if (cons->open == 1) {
232         printk("Console already open\n");
233         return NULL;
234     }
235
236
237     cons->width = width;
238     cons->height = height;
239
240     cons->queue = create_queue(CONSOLE_QUEUE_LEN);
241     spin_lock_init(&(cons->lock));
242     init_waitqueue_head(&(cons->intr_queue));
243
244     cons->guest = guest;
245
246     cons->open = 1;
247     cons->connected = 0;
248
249
250     return cons;
251 }
252
253 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
254     //    printk("Posting Console message\n");
255
256     while (enqueue(cons->queue, msg) == -1) {   
257         wake_up_interruptible(&(cons->intr_queue));
258         schedule();
259     }
260
261     wake_up_interruptible(&(cons->intr_queue));
262
263     return 0;
264 }
265
266
267 static int palacios_tty_cursor_set(void * console, int x, int y) {
268     struct palacios_console * cons = (struct palacios_console *)console;
269     struct cons_msg * msg = NULL;
270
271     if (cons->connected == 0) {
272         return 0;
273     }
274
275     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
276
277     msg->op = CONSOLE_CURS_SET;
278     msg->cursor.x = x;
279     msg->cursor.y = y;
280
281     return post_msg(cons, msg);
282 }
283
284 static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
285     struct palacios_console * cons = (struct palacios_console *) console;
286     struct cons_msg * msg = NULL;
287
288     if (cons->connected == 0) {
289         return 0;
290     }
291
292     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
293
294     msg->op = CONSOLE_CHAR_SET;
295     msg->character.x = x;
296     msg->character.y = y;
297     msg->character.c = c;
298     msg->character.style = style;
299
300     return post_msg(cons, msg);
301 }
302
303 static int palacios_tty_scroll(void * console, int lines) {
304     struct palacios_console * cons = (struct palacios_console *) console;
305     struct cons_msg * msg = NULL;
306
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_SCROLL;
315     msg->scroll.lines = lines;
316
317     return post_msg(cons, msg);
318 }
319
320 static int palacios_set_text_resolution(void * console, int cols, int rows) {
321     struct palacios_console * cons = (struct palacios_console *)console;
322     struct cons_msg * msg = NULL;
323
324     if (cons->connected == 0) {
325         return 0;
326     }
327
328     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
329     
330     msg->op = CONSOLE_RESOLUTION;
331     msg->resolution.cols = cols;
332     msg->resolution.rows = rows;
333
334     return post_msg(cons, msg);
335 }
336
337 static int palacios_tty_update(void * console) {
338     struct palacios_console * cons = (struct palacios_console *) console;
339     struct cons_msg * msg = NULL;
340
341     if (cons->connected == 0) {
342         return 0;
343     }
344
345     msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
346
347     msg->op = CONSOLE_UPDATE;
348
349     return post_msg(cons, msg);
350 }
351
352 static void palacios_tty_close(void * console) {
353     struct palacios_console * cons = (struct palacios_console *) console;
354
355     cons->open = 0;
356 }
357
358
359
360 static struct v3_console_hooks palacios_console_hooks = {
361     .open                       = palacios_tty_open,
362     .set_cursor                 = palacios_tty_cursor_set,
363     .set_character              = palacios_tty_character_set,
364     .scroll                     = palacios_tty_scroll,
365     .set_text_resolution        = palacios_set_text_resolution,
366     .update                     = palacios_tty_update,
367     .close                      = palacios_tty_close,
368 };
369
370
371
372 int palacios_init_console( void ) {
373     V3_Init_Console(&palacios_console_hooks);
374     
375     return 0;
376 }