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;
213 if (cons->open == 0) {
214 printk("Attempted to connect to unopened console\n");
218 spin_lock_irqsave(&(cons->lock), flags);
220 cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
223 printk("Error creating console inode\n");
229 v3_deliver_console_event(guest->v3_ctx, NULL);
230 spin_unlock_irqrestore(&(cons->lock), flags);
232 printk("Console connected\n");
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);
243 printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
246 printk("ERROR: Cannot open a console on a NULL guest\n");
250 if (cons->open == 1) {
251 printk("Console already open\n");
256 cons->queue = create_queue(CONSOLE_QUEUE_LEN);
257 spin_lock_init(&(cons->lock));
258 init_waitqueue_head(&(cons->intr_queue));
264 cons->height = height;
268 add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
273 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
274 // printk("Posting Console message\n");
276 while (enqueue(cons->queue, msg) == -1) {
277 wake_up_interruptible(&(cons->intr_queue));
281 wake_up_interruptible(&(cons->intr_queue));
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;
291 if (cons->connected == 0) {
295 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
297 msg->op = CONSOLE_CURS_SET;
301 return post_msg(cons, msg);
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;
308 if (cons->connected == 0) {
312 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
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;
320 return post_msg(cons, msg);
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;
328 if (cons->connected == 0) {
332 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
334 msg->op = CONSOLE_SCROLL;
335 msg->scroll.lines = lines;
337 return post_msg(cons, msg);
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;
344 if (cons->connected == 0) {
348 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
350 msg->op = CONSOLE_RESOLUTION;
351 msg->resolution.cols = cols;
352 msg->resolution.rows = rows;
354 return post_msg(cons, msg);
357 static int palacios_tty_update(void * console) {
358 struct palacios_console * cons = (struct palacios_console *) console;
359 struct cons_msg * msg = NULL;
361 if (cons->connected == 0) {
365 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
367 msg->op = CONSOLE_UPDATE;
369 return post_msg(cons, msg);
372 static void palacios_tty_close(void * console) {
373 struct palacios_console * cons = (struct palacios_console *) console;
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,
395 static int console_init( void ) {
396 V3_Init_Console(&palacios_console_hooks);
404 static struct linux_ext console_ext = {
406 .init = console_init,
413 register_extension(&console_ext);