1 /******************************************************************************
4 * Virtual console driver.
6 * Copyright (c) 2002-2004, K A Fraser.
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this source file (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy, modify,
14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 * and to permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 #include <linux/config.h>
31 #include <linux/version.h>
32 #include <linux/module.h>
33 #include <linux/errno.h>
34 #include <linux/signal.h>
35 #include <linux/sched.h>
36 #include <linux/interrupt.h>
37 #include <linux/tty.h>
38 #include <linux/tty_flip.h>
39 #include <linux/serial.h>
40 #include <linux/major.h>
41 #include <linux/ptrace.h>
42 #include <linux/ioport.h>
44 #include <linux/slab.h>
45 #include <linux/init.h>
46 #include <linux/console.h>
47 #include <linux/bootmem.h>
50 #include <asm/uaccess.h>
51 #include <asm-xen/xen-public/event_channel.h>
52 #include <asm-xen/hypervisor.h>
53 #include <asm-xen/evtchn.h>
54 #include <asm-xen/ctrl_if.h>
58 * 'xencons=off' [XC_OFF]: Console is disabled.
59 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
60 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
61 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
63 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
64 * warnings from standard distro startup scripts.
66 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
67 static int xc_num = -1;
69 static int __init xencons_setup(char *str)
74 if ( !strncmp(str, "ttyS", 4) )
76 else if ( !strncmp(str, "tty", 3) )
78 else if ( !strncmp(str, "off", 3) )
84 n = simple_strtol( str+4, &q, 10 );
85 if ( q > (str + 4) ) xc_num = n;
88 n = simple_strtol( str+3, &q, 10 );
89 if ( q > (str + 3) ) xc_num = n;
97 __setup("xencons=", xencons_setup);
99 /* The kernel and user-land drivers share a common transmit buffer. */
100 static unsigned int wbuf_size = 4096;
101 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
103 static unsigned int wc, wp; /* write_cons, write_prod */
105 static int __init xencons_bufsz_setup(char *str)
108 goal = simple_strtoul(str, NULL, 0);
109 while ( wbuf_size < goal )
113 __setup("xencons_bufsz=", xencons_bufsz_setup);
115 /* This lock protects accesses to the common transmit buffer. */
116 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
118 /* Common transmit-kick routine. */
119 static void __xencons_tx_flush(void);
121 /* This task is used to defer sending console data until there is space. */
122 static void xencons_tx_flush_task_routine(void *data);
124 static DECLARE_TQUEUE(xencons_tx_flush_task,
125 xencons_tx_flush_task_routine,
128 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
129 static struct tty_driver *xencons_driver;
131 static struct tty_driver xencons_driver;
135 /******************** Kernel console driver ********************************/
137 static void kcons_write(
138 struct console *c, const char *s, unsigned int count)
143 spin_lock_irqsave(&xencons_lock, flags);
145 for ( i = 0; i < count; i++ )
147 if ( (wp - wc) >= (wbuf_size - 1) )
149 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
150 wbuf[WBUF_MASK(wp++)] = '\r';
153 __xencons_tx_flush();
155 spin_unlock_irqrestore(&xencons_lock, flags);
158 static void kcons_write_dom0(
159 struct console *c, const char *s, unsigned int count)
163 while ( (count > 0) &&
164 ((rc = HYPERVISOR_console_io(
165 CONSOLEIO_write, count, (char *)s)) > 0) )
172 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
173 static struct tty_driver *kcons_device(struct console *c, int *index)
176 return xencons_driver;
179 static kdev_t kcons_device(struct console *c)
181 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
185 static struct console kcons_info = {
186 device: kcons_device,
187 flags: CON_PRINTBUFFER,
191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
193 static int __init xen_console_init(void)
196 void xen_console_init(void)
199 if ( xen_start_info.flags & SIF_INITDOMAIN )
201 if ( xc_mode == XC_DEFAULT )
203 kcons_info.write = kcons_write_dom0;
204 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
205 if ( xc_mode == XC_SERIAL )
206 kcons_info.flags |= CON_ENABLED;
211 if ( xc_mode == XC_DEFAULT )
213 kcons_info.write = kcons_write;
219 strcpy(kcons_info.name, "ttyS");
220 if ( xc_num == -1 ) xc_num = 0;
224 strcpy(kcons_info.name, "tty");
225 if ( xc_num == -1 ) xc_num = 1;
232 wbuf = alloc_bootmem(wbuf_size);
234 register_console(&kcons_info);
238 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
239 console_initcall(xen_console_init);
242 /*** Useful function for console debugging -- goes straight to Xen. ***/
243 asmlinkage int xprintk(const char *fmt, ...)
247 static char printk_buf[1024];
249 /* Emit the output into the temporary buffer */
251 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
254 /* Send the processed output directly to Xen. */
255 kcons_write_dom0(NULL, printk_buf, printk_len);
260 /*** Forcibly flush console data before dying. ***/
261 void xencons_force_flush(void)
266 /* Emergency console is synchronous, so there's nothing to flush. */
267 if ( xen_start_info.flags & SIF_INITDOMAIN )
271 * We use dangerous control-interface functions that require a quiescent
272 * system and no interrupts. Try to ensure this with a global cli().
274 local_irq_disable(); /* XXXsmp */
276 /* Spin until console data is flushed through to the domain controller. */
277 while ( (wc != wp) && !ctrl_if_transmitter_empty() )
279 /* Interrupts are disabled -- we must manually reap responses. */
280 ctrl_if_discard_responses();
282 if ( (sz = wp - wc) == 0 )
284 if ( sz > sizeof(msg.msg) )
285 sz = sizeof(msg.msg);
286 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
287 sz = wbuf_size - WBUF_MASK(wc);
289 msg.type = CMSG_CONSOLE;
290 msg.subtype = CMSG_CONSOLE_DATA;
292 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
294 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
300 /******************** User-space console driver (/dev/console) ************/
302 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
304 #define TTY_INDEX(_tty) ((_tty)->index)
306 static int xencons_refcount;
307 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
308 #define DRV(_d) (&(_d))
309 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
312 static struct termios *xencons_termios[MAX_NR_CONSOLES];
313 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
314 static struct tty_struct *xencons_tty;
315 static int xencons_priv_irq;
318 /* Non-privileged receive callback. */
319 static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
324 spin_lock_irqsave(&xencons_lock, flags);
325 if ( xencons_tty != NULL )
327 for ( i = 0; i < msg->length; i++ )
328 tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
329 tty_flip_buffer_push(xencons_tty);
331 spin_unlock_irqrestore(&xencons_lock, flags);
334 ctrl_if_send_response(msg);
337 /* Privileged and non-privileged transmit worker. */
338 static void __xencons_tx_flush(void)
340 int sz, work_done = 0;
343 if ( xen_start_info.flags & SIF_INITDOMAIN )
347 kcons_write_dom0(NULL, &x_char, 1);
355 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
356 sz = wbuf_size - WBUF_MASK(wc);
357 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
366 msg.type = CMSG_CONSOLE;
367 msg.subtype = CMSG_CONSOLE_DATA;
371 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
373 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
382 if ( sz > sizeof(msg.msg) )
383 sz = sizeof(msg.msg);
384 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
385 sz = wbuf_size - WBUF_MASK(wc);
387 msg.type = CMSG_CONSOLE;
388 msg.subtype = CMSG_CONSOLE_DATA;
390 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
392 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
394 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
401 if ( work_done && (xencons_tty != NULL) )
403 wake_up_interruptible(&xencons_tty->write_wait);
404 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
405 (xencons_tty->ldisc.write_wakeup != NULL) )
406 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
410 /* Non-privileged transmit kicker. */
411 static void xencons_tx_flush_task_routine(void *data)
414 spin_lock_irqsave(&xencons_lock, flags);
415 __xencons_tx_flush();
416 spin_unlock_irqrestore(&xencons_lock, flags);
419 /* Privileged receive callback and transmit kicker. */
420 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
421 struct pt_regs *regs)
423 static char rbuf[16];
427 spin_lock_irqsave(&xencons_lock, flags);
429 if ( xencons_tty != NULL )
432 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
433 for ( i = 0; i < l; i++ )
434 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
435 if ( xencons_tty->flip.count != 0 )
436 tty_flip_buffer_push(xencons_tty);
440 __xencons_tx_flush();
442 spin_unlock_irqrestore(&xencons_lock, flags);
447 static int xencons_write_room(struct tty_struct *tty)
449 return wbuf_size - (wp - wc);
452 static int xencons_chars_in_buffer(struct tty_struct *tty)
457 static void xencons_send_xchar(struct tty_struct *tty, char ch)
461 if ( TTY_INDEX(tty) != 0 )
464 spin_lock_irqsave(&xencons_lock, flags);
466 __xencons_tx_flush();
467 spin_unlock_irqrestore(&xencons_lock, flags);
470 static void xencons_throttle(struct tty_struct *tty)
472 if ( TTY_INDEX(tty) != 0 )
476 xencons_send_xchar(tty, STOP_CHAR(tty));
479 static void xencons_unthrottle(struct tty_struct *tty)
481 if ( TTY_INDEX(tty) != 0 )
489 xencons_send_xchar(tty, START_CHAR(tty));
493 static void xencons_flush_buffer(struct tty_struct *tty)
497 if ( TTY_INDEX(tty) != 0 )
500 spin_lock_irqsave(&xencons_lock, flags);
502 spin_unlock_irqrestore(&xencons_lock, flags);
505 static inline int __xencons_put_char(int ch)
508 if ( (wp - wc) == wbuf_size )
510 wbuf[WBUF_MASK(wp++)] = _ch;
514 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
515 static int xencons_write(
516 struct tty_struct *tty,
517 const unsigned char *buf,
523 if ( TTY_INDEX(tty) != 0 )
526 spin_lock_irqsave(&xencons_lock, flags);
528 for ( i = 0; i < count; i++ )
529 if ( !__xencons_put_char(buf[i]) )
533 __xencons_tx_flush();
535 spin_unlock_irqrestore(&xencons_lock, flags);
540 static int xencons_write(
541 struct tty_struct *tty,
549 if ( from_user && verify_area(VERIFY_READ, buf, count) )
552 if ( TTY_INDEX(tty) != 0 )
555 spin_lock_irqsave(&xencons_lock, flags);
557 for ( i = 0; i < count; i++ )
561 __get_user(ch, buf + i);
564 if ( !__xencons_put_char(ch) )
569 __xencons_tx_flush();
571 spin_unlock_irqrestore(&xencons_lock, flags);
577 static void xencons_put_char(struct tty_struct *tty, u_char ch)
581 if ( TTY_INDEX(tty) != 0 )
584 spin_lock_irqsave(&xencons_lock, flags);
585 (void)__xencons_put_char(ch);
586 spin_unlock_irqrestore(&xencons_lock, flags);
589 static void xencons_flush_chars(struct tty_struct *tty)
593 if ( TTY_INDEX(tty) != 0 )
596 spin_lock_irqsave(&xencons_lock, flags);
597 __xencons_tx_flush();
598 spin_unlock_irqrestore(&xencons_lock, flags);
601 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
603 unsigned long orig_jiffies = jiffies;
605 if ( TTY_INDEX(tty) != 0 )
608 while ( DRV(tty->driver)->chars_in_buffer(tty) )
610 set_current_state(TASK_INTERRUPTIBLE);
612 if ( signal_pending(current) )
614 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
618 set_current_state(TASK_RUNNING);
621 static int xencons_open(struct tty_struct *tty, struct file *filp)
625 if ( TTY_INDEX(tty) != 0 )
628 spin_lock_irqsave(&xencons_lock, flags);
629 tty->driver_data = NULL;
630 if ( xencons_tty == NULL )
632 __xencons_tx_flush();
633 spin_unlock_irqrestore(&xencons_lock, flags);
638 static void xencons_close(struct tty_struct *tty, struct file *filp)
642 if ( TTY_INDEX(tty) != 0 )
645 if ( tty->count == 1 )
648 tty_wait_until_sent(tty, 0);
649 if ( DRV(tty->driver)->flush_buffer != NULL )
650 DRV(tty->driver)->flush_buffer(tty);
651 if ( tty->ldisc.flush_buffer != NULL )
652 tty->ldisc.flush_buffer(tty);
654 spin_lock_irqsave(&xencons_lock, flags);
656 spin_unlock_irqrestore(&xencons_lock, flags);
660 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
661 static struct tty_operations xencons_ops = {
662 .open = xencons_open,
663 .close = xencons_close,
664 .write = xencons_write,
665 .write_room = xencons_write_room,
666 .put_char = xencons_put_char,
667 .flush_chars = xencons_flush_chars,
668 .chars_in_buffer = xencons_chars_in_buffer,
669 .send_xchar = xencons_send_xchar,
670 .flush_buffer = xencons_flush_buffer,
671 .throttle = xencons_throttle,
672 .unthrottle = xencons_unthrottle,
673 .wait_until_sent = xencons_wait_until_sent,
676 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
677 static const char *xennullcon_startup(void)
682 static int xennullcon_dummy(void)
687 #define DUMMY (void *)xennullcon_dummy
690 * The console `switch' structure for the dummy console
692 * Most of the operations are dummies.
695 const struct consw xennull_con = {
696 .owner = THIS_MODULE,
697 .con_startup = xennullcon_startup,
708 .con_font_set = DUMMY,
709 .con_font_get = DUMMY,
710 .con_font_default = DUMMY,
711 .con_font_copy = DUMMY,
712 .con_set_palette = DUMMY,
713 .con_scrolldelta = DUMMY,
718 static int __init xencons_init(void)
722 if ( xc_mode == XC_OFF )
725 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
726 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
727 1 : MAX_NR_CONSOLES);
728 if ( xencons_driver == NULL )
731 memset(&xencons_driver, 0, sizeof(struct tty_driver));
732 xencons_driver.magic = TTY_DRIVER_MAGIC;
733 xencons_driver.refcount = &xencons_refcount;
734 xencons_driver.table = xencons_table;
735 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
738 DRV(xencons_driver)->major = TTY_MAJOR;
739 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
740 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
741 DRV(xencons_driver)->init_termios = tty_std_termios;
742 DRV(xencons_driver)->flags =
743 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
744 DRV(xencons_driver)->termios = xencons_termios;
745 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
747 if ( xc_mode == XC_SERIAL )
749 DRV(xencons_driver)->name = "ttyS";
750 DRV(xencons_driver)->minor_start = 64 + xc_num;
751 DRV(xencons_driver)->name_base = 0 + xc_num;
755 DRV(xencons_driver)->name = "tty";
756 DRV(xencons_driver)->minor_start = xc_num;
757 DRV(xencons_driver)->name_base = xc_num;
760 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
761 tty_set_operations(xencons_driver, &xencons_ops);
763 xencons_driver.open = xencons_open;
764 xencons_driver.close = xencons_close;
765 xencons_driver.write = xencons_write;
766 xencons_driver.write_room = xencons_write_room;
767 xencons_driver.put_char = xencons_put_char;
768 xencons_driver.flush_chars = xencons_flush_chars;
769 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
770 xencons_driver.send_xchar = xencons_send_xchar;
771 xencons_driver.flush_buffer = xencons_flush_buffer;
772 xencons_driver.throttle = xencons_throttle;
773 xencons_driver.unthrottle = xencons_unthrottle;
774 xencons_driver.wait_until_sent = xencons_wait_until_sent;
777 if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
779 printk("WARNING: Failed to register Xen virtual "
780 "console driver as '%s%d'\n",
781 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
782 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
783 put_tty_driver(xencons_driver);
784 xencons_driver = NULL;
789 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
790 tty_register_device(xencons_driver, 0, NULL);
793 if ( xen_start_info.flags & SIF_INITDOMAIN )
795 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
796 (void)request_irq(xencons_priv_irq,
797 xencons_priv_interrupt, 0, "console", NULL);
801 (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
804 printk("Xen virtual console successfully installed as %s%d\n",
805 DRV(xencons_driver)->name,
806 DRV(xencons_driver)->name_base );
811 module_init(xencons_init);