6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.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>
16 #include <interfaces/vmm_console.h>
17 #include <palacios/vmm_host_events.h>
21 #include "util-queue.h"
22 #include "linux-exts.h"
24 typedef enum { CONSOLE_CURS_SET = 1,
28 CONSOLE_RESOLUTION = 5} console_op_t;
32 struct palacios_console {
33 struct gen_queue * queue;
39 wait_queue_head_t intr_queue;
44 struct v3_guest * guest;
52 } __attribute__((packed));
54 struct character_msg {
59 } __attribute__((packed));
63 } __attribute__((packed));
66 struct resolution_msg {
69 } __attribute__((packed));
74 struct cursor_msg cursor;
75 struct character_msg character;
76 struct scroll_msg scroll;
77 struct resolution_msg resolution;
79 } __attribute__((packed));
82 /* This is overkill...*/
83 #define CONSOLE_QUEUE_LEN 8096
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;
93 if (cons->open == 0) {
98 if (size < sizeof(struct cons_msg)) {
99 printk("Invalid Read operation size: %lu\n", size);
103 msg = dequeue(cons->queue);
106 printk("ERROR: Null console message\n");
110 if (copy_to_user(buf, msg, size)) {
111 printk("Read Fault\n");
118 spin_lock_irqsave(&(cons->queue->lock), flags);
119 entries = cons->queue->num_entries;
120 spin_unlock_irqrestore(&(cons->queue->lock), flags);
123 wake_up_interruptible(&(cons->intr_queue));
126 // printk("Read from console\n");
132 console_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
133 struct palacios_console * cons = filp->private_data;
135 struct v3_keyboard_event event = {0, 0};
137 if (cons->open == 0) {
142 for (i = 0; i < size; i++) {
143 if (copy_from_user(&(event.scan_code), buf++, 1)) {
144 printk("Console Write fault\n");
148 v3_deliver_keyboard_event(cons->guest->v3_ctx, &event);
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;
161 // printk("Console=%p (guest=%s)\n", cons, cons->guest->name);
164 poll_wait(filp, &(cons->intr_queue), poll_tb);
166 spin_lock_irqsave(&(cons->queue->lock), flags);
167 entries = cons->queue->num_entries;
168 spin_unlock_irqrestore(&(cons->queue->lock), flags);
171 // printk("Returning from POLL\n");
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;
184 printk("Releasing the Console File desc\n");
186 spin_lock_irqsave(&(cons->queue->lock), flags);
188 spin_unlock_irqrestore(&(cons->queue->lock), flags);
190 while ((msg = dequeue(cons->queue))) {
198 static struct file_operations cons_fops = {
199 .read = console_read,
200 .write = console_write,
201 .poll = console_poll,
202 .release = console_release,
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;
214 if (cons->open == 0) {
215 printk("Attempted to connect to unopened console\n");
219 spin_lock_irqsave(&(cons->lock), flags);
220 if (cons->connected == 0) {
224 spin_unlock_irqrestore(&(cons->lock), flags);
227 printk("Console already connected\n");
231 cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
234 printk("Error creating console inode\n");
238 v3_deliver_console_event(guest->v3_ctx, NULL);
241 printk("Console connected\n");
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);
252 printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
255 printk("ERROR: Cannot open a console on a NULL guest\n");
259 if (cons->open == 1) {
260 printk("Console already open\n");
265 cons->queue = create_queue(CONSOLE_QUEUE_LEN);
266 spin_lock_init(&(cons->lock));
267 init_waitqueue_head(&(cons->intr_queue));
273 cons->height = height;
277 add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
282 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
283 // printk("Posting Console message\n");
285 while (enqueue(cons->queue, msg) == -1) {
286 wake_up_interruptible(&(cons->intr_queue));
290 wake_up_interruptible(&(cons->intr_queue));
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;
300 if (cons->connected == 0) {
304 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
306 msg->op = CONSOLE_CURS_SET;
310 return post_msg(cons, msg);
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;
317 if (cons->connected == 0) {
321 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
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;
329 return post_msg(cons, msg);
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;
337 if (cons->connected == 0) {
341 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
343 msg->op = CONSOLE_SCROLL;
344 msg->scroll.lines = lines;
346 return post_msg(cons, msg);
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;
353 if (cons->connected == 0) {
357 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
359 msg->op = CONSOLE_RESOLUTION;
360 msg->resolution.cols = cols;
361 msg->resolution.rows = rows;
363 return post_msg(cons, msg);
366 static int palacios_tty_update(void * console) {
367 struct palacios_console * cons = (struct palacios_console *) console;
368 struct cons_msg * msg = NULL;
370 if (cons->connected == 0) {
374 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
376 msg->op = CONSOLE_UPDATE;
378 return post_msg(cons, msg);
381 static void palacios_tty_close(void * console) {
382 struct palacios_console * cons = (struct palacios_console *) console;
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,
404 static int console_init( void ) {
405 V3_Init_Console(&palacios_console_hooks);
413 static struct linux_ext console_ext = {
415 .init = console_init,
422 register_extension(&console_ext);