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 <palacios/vmm_console.h>
17 #include <palacios/vmm_host_events.h>
20 #include "palacios-console.h"
21 #include "palacios-queue.h"
23 typedef enum { CONSOLE_CURS_SET = 1,
27 CONSOLE_RESOLUTION = 5} console_op_t;
34 } __attribute__((packed));
36 struct character_msg {
41 } __attribute__((packed));
45 } __attribute__((packed));
48 struct resolution_msg {
51 } __attribute__((packed));
56 struct cursor_msg cursor;
57 struct character_msg character;
58 struct scroll_msg scroll;
59 struct resolution_msg resolution;
61 } __attribute__((packed));
64 /* This is overkill...*/
65 #define CONSOLE_QUEUE_LEN 8096
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;
75 if (cons->open == 0) {
80 if (size < sizeof(struct cons_msg)) {
81 printk("Invalid Read operation size: %lu\n", size);
85 msg = dequeue(cons->queue);
88 printk("ERROR: Null console message\n");
92 if (copy_to_user(buf, msg, size)) {
93 printk("Read Fault\n");
100 spin_lock_irqsave(&(cons->queue->lock), flags);
101 entries = cons->queue->num_entries;
102 spin_unlock_irqrestore(&(cons->queue->lock), flags);
105 wake_up_interruptible(&(cons->intr_queue));
108 // printk("Read from console\n");
114 console_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
115 struct palacios_console * cons = filp->private_data;
117 struct v3_keyboard_event event = {0, 0};
119 if (cons->open == 0) {
124 for (i = 0; i < size; i++) {
125 if (copy_from_user(&(event.scan_code), buf, 1)) {
126 printk("Console Write fault\n");
130 v3_deliver_keyboard_event(cons->guest->v3_ctx, &event);
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;
143 // printk("Console=%p (guest=%s)\n", cons, cons->guest->name);
146 poll_wait(filp, &(cons->intr_queue), poll_tb);
148 spin_lock_irqsave(&(cons->queue->lock), flags);
149 entries = cons->queue->num_entries;
150 spin_unlock_irqrestore(&(cons->queue->lock), flags);
153 // printk("Returning from POLL\n");
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;
166 printk("Releasing the Console File desc\n");
168 spin_lock_irqsave(&(cons->queue->lock), flags);
170 spin_unlock_irqrestore(&(cons->queue->lock), flags);
172 while ((msg = dequeue(cons->queue))) {
180 static struct file_operations cons_fops = {
181 .read = console_read,
182 .write = console_write,
183 .poll = console_poll,
184 .release = console_release,
189 int connect_console(struct v3_guest * guest) {
190 struct palacios_console * cons = &(guest->console);
194 if (cons->open == 0) {
195 printk("Attempted to connect to unopened console\n");
199 spin_lock_irqsave(&(cons->lock), flags);
201 cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
204 printk("Error creating console inode\n");
210 v3_deliver_console_event(guest->v3_ctx, NULL);
211 spin_unlock_irqrestore(&(cons->lock), flags);
213 printk("Console connected\n");
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);
224 printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
227 printk("ERROR: Cannot open a console on a NULL guest\n");
231 if (cons->open == 1) {
232 printk("Console already open\n");
238 cons->height = height;
240 cons->queue = create_queue(CONSOLE_QUEUE_LEN);
241 spin_lock_init(&(cons->lock));
242 init_waitqueue_head(&(cons->intr_queue));
253 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
254 // printk("Posting Console message\n");
256 while (enqueue(cons->queue, msg) == -1) {
257 wake_up_interruptible(&(cons->intr_queue));
261 wake_up_interruptible(&(cons->intr_queue));
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;
271 if (cons->connected == 0) {
275 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
277 msg->op = CONSOLE_CURS_SET;
281 return post_msg(cons, msg);
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;
288 if (cons->connected == 0) {
292 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
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;
300 return post_msg(cons, msg);
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;
308 if (cons->connected == 0) {
312 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
314 msg->op = CONSOLE_SCROLL;
315 msg->scroll.lines = lines;
317 return post_msg(cons, msg);
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;
324 if (cons->connected == 0) {
328 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
330 msg->op = CONSOLE_RESOLUTION;
331 msg->resolution.cols = cols;
332 msg->resolution.rows = rows;
334 return post_msg(cons, msg);
337 static int palacios_tty_update(void * console) {
338 struct palacios_console * cons = (struct palacios_console *) console;
339 struct cons_msg * msg = NULL;
341 if (cons->connected == 0) {
345 msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
347 msg->op = CONSOLE_UPDATE;
349 return post_msg(cons, msg);
352 static void palacios_tty_close(void * console) {
353 struct palacios_console * cons = (struct palacios_console *) console;
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,
372 int palacios_init_console( void ) {
373 V3_Init_Console(&palacios_console_hooks);