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 ERROR("Invalid Read operation size: %lu\n", size);
103 msg = dequeue(cons->queue);
106 ERROR("ERROR: Null console message\n");
110 if (copy_to_user(buf, msg, size)) {
111 ERROR("Read Fault\n");
118 palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
119 entries = cons->queue->num_entries;
120 palacios_spinlock_unlock_irqrestore(&(cons->queue->lock), flags);
123 wake_up_interruptible(&(cons->intr_queue));
126 // DEBUG("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 + i, 1)) {
144 ERROR("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 // DEBUG("Console=%p (guest=%s)\n", cons, cons->guest->name);
164 poll_wait(filp, &(cons->intr_queue), poll_tb);
166 palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
167 entries = cons->queue->num_entries;
168 palacios_spinlock_unlock_irqrestore(&(cons->queue->lock), flags);
171 // DEBUG("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 DEBUG("Releasing the Console File desc\n");
186 palacios_spinlock_lock_irqsave(&(cons->queue->lock), flags);
188 palacios_spinlock_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 ERROR("Attempted to connect to unopened console\n");
219 palacios_spinlock_lock_irqsave(&(cons->lock), flags);
220 if (cons->connected == 0) {
224 palacios_spinlock_unlock_irqrestore(&(cons->lock), flags);
227 ERROR("Console already connected\n");
231 cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, O_RDWR);
234 ERROR("Error creating console inode\n");
238 v3_deliver_console_event(guest->v3_ctx, NULL);
241 INFO("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 = palacios_alloc(sizeof(struct palacios_console));
253 ERROR("Cannot allocate memory for console\n");
257 INFO("Guest initialized virtual console (Guest=%s)\n", guest->name);
260 ERROR("ERROR: Cannot open a console on a NULL guest\n");
265 if (cons->open == 1) {
266 ERROR("Console already open\n");
272 cons->queue = create_queue(CONSOLE_QUEUE_LEN);
273 palacios_spinlock_init(&(cons->lock));
274 init_waitqueue_head(&(cons->intr_queue));
280 cons->height = height;
284 add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
289 static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
290 // DEBUG("Posting Console message\n");
292 while (enqueue(cons->queue, msg) == -1) {
293 wake_up_interruptible(&(cons->intr_queue));
297 wake_up_interruptible(&(cons->intr_queue));
303 static int palacios_tty_cursor_set(void * console, int x, int y) {
304 struct palacios_console * cons = (struct palacios_console *)console;
305 struct cons_msg * msg = NULL;
307 if (cons->connected == 0) {
311 msg = palacios_alloc(sizeof(struct cons_msg));
314 ERROR("Cannot allocate cursor set message in console\n");
318 msg->op = CONSOLE_CURS_SET;
322 return post_msg(cons, msg);
325 static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
326 struct palacios_console * cons = (struct palacios_console *) console;
327 struct cons_msg * msg = NULL;
329 if (cons->connected == 0) {
333 msg = palacios_alloc(sizeof(struct cons_msg));
336 ERROR("Cannot allocate character set message in console\n");
340 msg->op = CONSOLE_CHAR_SET;
341 msg->character.x = x;
342 msg->character.y = y;
343 msg->character.c = c;
344 msg->character.style = style;
346 return post_msg(cons, msg);
349 static int palacios_tty_scroll(void * console, int lines) {
350 struct palacios_console * cons = (struct palacios_console *) console;
351 struct cons_msg * msg = NULL;
354 if (cons->connected == 0) {
358 msg = palacios_alloc(sizeof(struct cons_msg));
361 ERROR("Cannot allocate scroll message in console\n");
365 msg->op = CONSOLE_SCROLL;
366 msg->scroll.lines = lines;
368 return post_msg(cons, msg);
371 static int palacios_set_text_resolution(void * console, int cols, int rows) {
372 struct palacios_console * cons = (struct palacios_console *)console;
373 struct cons_msg * msg = NULL;
375 if (cons->connected == 0) {
379 msg = palacios_alloc(sizeof(struct cons_msg));
382 ERROR("Cannot allocate text resolution message in console\n");
386 msg->op = CONSOLE_RESOLUTION;
387 msg->resolution.cols = cols;
388 msg->resolution.rows = rows;
390 return post_msg(cons, msg);
393 static int palacios_tty_update(void * console) {
394 struct palacios_console * cons = (struct palacios_console *) console;
395 struct cons_msg * msg = NULL;
397 if (cons->connected == 0) {
401 msg = palacios_alloc(sizeof(struct cons_msg));
404 ERROR("Cannot allocate update message in console\n");
408 msg->op = CONSOLE_UPDATE;
410 return post_msg(cons, msg);
413 static void palacios_tty_close(void * console) {
414 struct palacios_console * cons = (struct palacios_console *) console;
418 remove_guest_ctrl(cons->guest, V3_VM_CONSOLE_CONNECT);
419 deinit_queue(cons->queue);
421 palacios_spinlock_deinit(&(cons->lock));
428 static struct v3_console_hooks palacios_console_hooks = {
429 .open = palacios_tty_open,
430 .set_cursor = palacios_tty_cursor_set,
431 .set_character = palacios_tty_character_set,
432 .scroll = palacios_tty_scroll,
433 .set_text_resolution = palacios_set_text_resolution,
434 .update = palacios_tty_update,
435 .close = palacios_tty_close,
443 static int console_init( void ) {
444 V3_Init_Console(&palacios_console_hooks);
449 static int console_deinit(void)
457 static struct linux_ext console_ext = {
459 .init = console_init,
460 .deinit = console_deinit,
466 register_extension(&console_ext);