2 * Copyright (c) 2015 Julien Grall <julien.grall@citrix.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/module.h>
32 #include <sys/systm.h>
33 #include <sys/consio.h>
38 #include <sys/systm.h>
39 #include <sys/taskqueue.h>
41 #include <sys/kernel.h>
47 #include <machine/stdarg.h>
49 #include <xen/xen-os.h>
50 #include <xen/hypervisor.h>
51 #include <xen/xen_intr.h>
52 #include <xen/interface/io/console.h>
55 #include "opt_printf.h"
61 static char driver_name[] = "xc";
65 typedef void xencons_early_init_t(struct xencons_priv *cons);
66 typedef int xencons_init_t(device_t dev, struct tty *tp,
67 driver_intr_t intr_handler);
68 typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
70 typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
75 * Called by the low-level driver during early boot.
76 * Only the minimal set up to get a console should be done here.
78 xencons_early_init_t *early_init;
79 /* Prepare the console to be fully use */
81 /* Read/write helpers */
83 xencons_write_t *write;
87 /* Mutex to protect the shared ring and the internal buffers */
89 /* Interrupt handler used for notify the backend */
90 xen_intr_handle_t intr_handle;
91 /* KDB internal state */
95 /* Status of the tty */
97 /* Callout used when the write buffer is full */
98 struct callout callout;
100 /* Internal buffers must be used with mtx locked */
101 #define WBUF_SIZE 4096
102 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
103 char wbuf[WBUF_SIZE];
104 unsigned int wc, wp; /* Consumer/producer wbuf */
106 #define RBUF_SIZE 1024
107 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
108 char rbuf[RBUF_SIZE];
109 unsigned int rc, rp; /* Consumer/producer rbuf */
111 /* Pointer to the console operations */
112 const struct xencons_ops *ops;
115 * Ring specific fields
116 * XXX: make an union?
118 /* Event channel number for early notification (PV only) */
120 /* Console shared page */
121 struct xencons_interface *intf;
125 * Data for the main console
126 * Necessary to support low-level console driver
128 static struct xencons_priv main_cons;
130 #define XC_POLLTIME (hz/10)
133 * Virtual address of the shared console page (only for PV guest)
134 * TODO: Introduce a function to set it
138 /*----------------------------- Debug function ------------------------------*/
146 putchar(int c, void *arg)
148 struct putchar_arg *pca;
150 pca = (struct putchar_arg *)arg;
152 if (pca->buf == NULL) {
154 * We have no buffer, output directly to the
155 * console char by char.
157 HYPERVISOR_console_write((char *)&c, 1);
159 pca->buf[pca->n_next++] = c;
160 if ((pca->size == pca->n_next) || (c = '\0')) {
161 /* Flush the buffer */
162 HYPERVISOR_console_write(pca->buf, pca->n_next);
169 xc_printf(const char *fmt, ...)
172 struct putchar_arg pca;
173 #ifdef PRINTF_BUFR_SIZE
174 char buf[PRINTF_BUFR_SIZE];
177 pca.size = sizeof(buf);
184 KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
187 kvprintf(fmt, putchar, &pca, 10, ap);
190 #ifdef PRINTF_BUFR_SIZE
192 HYPERVISOR_console_write(buf, pca.n_next);
196 /*---------------------- Helpers for the console lock -----------------------*/
198 * The lock is not used when the kernel is panicing as it will never recover
199 * and we want to output no matter what it costs.
201 static inline void xencons_lock(struct xencons_priv *cons)
204 if (panicstr == NULL)
205 mtx_lock_spin(&cons->mtx);
209 static inline void xencons_unlock(struct xencons_priv *cons)
212 if (panicstr == NULL)
213 mtx_unlock_spin(&cons->mtx);
216 #define xencons_lock_assert(cons) mtx_assert(&(cons)->mtx, MA_OWNED)
218 /*------------------ Helpers for the hypervisor console ---------------------*/
220 xencons_early_init_hypervisor(struct xencons_priv *cons)
223 * Nothing to setup for the low-level console when using
224 * the hypervisor console.
229 xencons_init_hypervisor(device_t dev, struct tty *tp,
230 driver_intr_t intr_handler)
232 struct xencons_priv *cons;
235 cons = tty_softc(tp);
237 err = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
238 intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
240 device_printf(dev, "Can't register console interrupt\n");
246 xencons_write_hypervisor(struct xencons_priv *cons, const char *buffer,
250 HYPERVISOR_console_io(CONSOLEIO_write, size, buffer);
256 xencons_read_hypervisor(struct xencons_priv *cons, char *buffer,
260 xencons_lock_assert(cons);
262 return (HYPERVISOR_console_io(CONSOLEIO_read, size, buffer));
265 static const struct xencons_ops xencons_hypervisor_ops = {
266 .early_init = xencons_early_init_hypervisor,
267 .init = xencons_init_hypervisor,
268 .read = xencons_read_hypervisor,
269 .write = xencons_write_hypervisor,
272 /*------------------ Helpers for the ring console ---------------------------*/
274 xencons_early_init_ring(struct xencons_priv *cons)
276 /* The shared page for PV is already mapped by the boot code */
277 cons->intf = (struct xencons_interface *)console_page;
278 cons->evtchn = HYPERVISOR_start_info->console.domU.evtchn;
282 xencons_init_ring(device_t dev, struct tty *tp, driver_intr_t intr_handler)
284 struct xencons_priv *cons;
287 cons = tty_softc(tp);
289 if (cons->evtchn == 0)
292 err = xen_intr_bind_local_port(dev, cons->evtchn, NULL,
293 intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
301 xencons_notify_ring(struct xencons_priv *cons)
304 * The console may be used before the ring interrupt is properly
306 * If so, fallback to directly use the event channel hypercall.
308 if (__predict_true(cons->intr_handle != NULL))
309 xen_intr_signal(cons->intr_handle);
311 struct evtchn_send send = {
315 HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
320 xencons_write_ring(struct xencons_priv *cons, const char *buffer,
323 struct xencons_interface *intf;
324 XENCONS_RING_IDX wcons, wprod;
329 xencons_lock_assert(cons);
331 wcons = intf->out_cons;
332 wprod = intf->out_prod;
335 KASSERT((wprod - wcons) <= sizeof(intf->out),
336 ("console send ring inconsistent"));
338 for (sent = 0; sent < size; sent++, wprod++) {
339 if ((wprod - wcons) >= sizeof(intf->out))
341 intf->out[MASK_XENCONS_IDX(wprod, intf->out)] = buffer[sent];
345 intf->out_prod = wprod;
347 xencons_notify_ring(cons);
353 xencons_read_ring(struct xencons_priv *cons, char *buffer, unsigned int size)
355 struct xencons_interface *intf;
356 XENCONS_RING_IDX rcons, rprod;
361 xencons_lock_assert(cons);
363 rcons = intf->in_cons;
364 rprod = intf->in_prod;
367 for (rsz = 0; rsz < size; rsz++, rcons++) {
370 buffer[rsz] = intf->in[MASK_XENCONS_IDX(rcons, intf->in)];
374 intf->in_cons = rcons;
376 /* No need to notify the backend if nothing has been read */
378 xencons_notify_ring(cons);
383 static const struct xencons_ops xencons_ring_ops = {
384 .early_init = xencons_early_init_ring,
385 .init = xencons_init_ring,
386 .read = xencons_read_ring,
387 .write = xencons_write_ring,
390 /*------------------ Common implementation of the console -------------------*/
393 * Called by the low-level driver during early boot to initialize the
394 * main console driver.
395 * Only the minimal set up to get a console should be done here.
398 xencons_early_init(void)
401 mtx_init(&main_cons.mtx, "XCONS LOCK", NULL, MTX_SPIN);
403 if (xen_initial_domain())
404 main_cons.ops = &xencons_hypervisor_ops;
406 main_cons.ops = &xencons_ring_ops;
408 main_cons.ops->early_init(&main_cons);
412 * Receive character from the console and put them in the internal buffer
413 * XXX: Handle overflow of the internal buffer
416 xencons_rx(struct xencons_priv *cons)
422 while ((sz = cons->ops->read(cons, buf, sizeof(buf))) > 0) {
425 for (i = 0; i < sz; i++)
426 cons->rbuf[RBUF_MASK(cons->rp++)] = buf[i];
428 xencons_unlock(cons);
431 /* Return true if the write buffer is full */
433 xencons_tx_full(struct xencons_priv *cons)
438 used = cons->wp - cons->wc;
439 xencons_unlock(cons);
441 return (used >= WBUF_SIZE);
445 xencons_tx_flush(struct xencons_priv *cons, int force)
450 while (cons->wc != cons->wp) {
452 sz = cons->wp - cons->wc;
453 if (sz > (WBUF_SIZE - WBUF_MASK(cons->wc)))
454 sz = WBUF_SIZE - WBUF_MASK(cons->wc);
455 sent = cons->ops->write(cons, &cons->wbuf[WBUF_MASK(cons->wc)],
459 * The other end may not have been initialized. Ignore
462 if (__predict_false(sent < 0))
466 * If force is set, spin until the console data is
467 * flushed through the domain controller.
469 if (sent == 0 && __predict_true(!force))
474 xencons_unlock(cons);
478 xencons_putc(struct xencons_priv *cons, int c, bool force_flush)
482 if ((cons->wp - cons->wc) < WBUF_SIZE)
483 cons->wbuf[WBUF_MASK(cons->wp++)] = c;
484 xencons_unlock(cons);
486 xencons_tx_flush(cons, force_flush);
488 return (xencons_tx_full(cons));
492 xencons_getc(struct xencons_priv *cons)
497 if (cons->rp != cons->rc) {
498 /* We need to return only one char */
499 ret = (int)cons->rbuf[RBUF_MASK(cons->rc)];
505 xencons_unlock(cons);
511 xencons_tx(struct tty *tp)
515 struct xencons_priv *cons;
517 cons = tty_softc(tp);
519 tty_lock_assert(tp, MA_OWNED);
522 * Don't transmit any character if the buffer is full. Otherwise,
523 * characters may be lost
525 if (xencons_tx_full(cons))
529 while (!cons_full && ttydisc_getc(tp, &c, 1) == 1)
530 cons_full = xencons_putc(cons, c, false);
536 xencons_intr(void *arg)
539 struct xencons_priv *cons;
543 cons = tty_softc(tp);
546 * The input will be used by the low-level console when KDB is active
552 * It's not necessary to retrieve input when the tty is not opened
560 while ((ret = xencons_getc(cons)) != -1) {
562 kdb_alt_break(ret, &cons->altbrk);
564 ttydisc_rint(tp, ret, 0);
566 ttydisc_rint_done(tp);
569 /* Try to flush remaining characters if necessary */
570 xencons_tx_flush(cons, 0);
574 * Helpers to call while shutting down:
575 * - Force flush all output
578 xencons_shutdown(void *arg, int howto)
584 xencons_tx_flush(tty_softc(tp), 1);
587 /*---------------------- Low-level console driver ---------------------------*/
589 xencons_cnprobe(struct consdev *cp)
592 if (!xen_pv_domain())
595 cp->cn_pri = CN_REMOTE;
596 sprintf(cp->cn_name, "%s0", driver_name);
600 xencons_cninit(struct consdev *cp)
603 xencons_early_init();
607 xencons_cnterm(struct consdev *cp)
612 xencons_cngrab(struct consdev *cp)
617 xencons_cnungrab(struct consdev *cp)
622 xencons_cngetc(struct consdev *dev)
625 xencons_rx(&main_cons);
627 return (xencons_getc(&main_cons));
631 xencons_cnputc(struct consdev *dev, int c)
634 * The low-level console is used by KDB and panic. We have to ensure
635 * that any character sent will be seen by the backend.
637 xencons_putc(&main_cons, c, true);
640 CONSOLE_DRIVER(xencons);
642 /*----------------------------- TTY driver ---------------------------------*/
645 xencons_tty_open(struct tty *tp)
647 struct xencons_priv *cons;
649 cons = tty_softc(tp);
657 xencons_tty_close(struct tty *tp)
659 struct xencons_priv *cons;
661 cons = tty_softc(tp);
663 cons->opened = false;
667 xencons_timeout(void *v)
670 struct xencons_priv *cons;
673 cons = tty_softc(tp);
676 callout_reset(&cons->callout, XC_POLLTIME,
677 xencons_timeout, tp);
681 xencons_tty_outwakeup(struct tty *tp)
683 struct xencons_priv *cons;
685 cons = tty_softc(tp);
687 callout_stop(&cons->callout);
690 callout_reset(&cons->callout, XC_POLLTIME,
691 xencons_timeout, tp);
694 static struct ttydevsw xencons_ttydevsw = {
695 .tsw_flags = TF_NOPREFIX,
696 .tsw_open = xencons_tty_open,
697 .tsw_close = xencons_tty_close,
698 .tsw_outwakeup = xencons_tty_outwakeup,
701 /*------------------------ Main console driver ------------------------------*/
703 xencons_identify(driver_t *driver, device_t parent)
707 #if defined(__arm__) || defined(__aarch64__)
711 if (!xen_pv_domain())
715 child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
719 xencons_probe(device_t dev)
722 device_set_desc(dev, "Xen Console");
723 return (BUS_PROBE_NOWILDCARD);
727 xencons_attach(device_t dev)
731 * The main console is already allocated statically in order to
732 * support low-level console
734 struct xencons_priv *cons;
739 tp = tty_alloc(&xencons_ttydevsw, cons);
740 tty_makedev(tp, NULL, "%s%r", driver_name, 0);
741 device_set_softc(dev, tp);
743 callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
745 err = cons->ops->init(dev, tp, xencons_intr);
747 device_printf(dev, "Unable to initialize the console (%d)\n",
752 /* register handler to flush console on shutdown */
753 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
754 tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
755 device_printf(dev, "shutdown event registration failed!\n");
761 xencons_resume(device_t dev)
763 struct xencons_priv *cons;
767 tp = device_get_softc(dev);
768 cons = tty_softc(tp);
769 xen_intr_unbind(&cons->intr_handle);
771 err = cons->ops->init(dev, tp, xencons_intr);
773 device_printf(dev, "Unable to resume the console (%d)\n", err);
780 static devclass_t xencons_devclass;
782 static device_method_t xencons_methods[] = {
783 DEVMETHOD(device_identify, xencons_identify),
784 DEVMETHOD(device_probe, xencons_probe),
785 DEVMETHOD(device_attach, xencons_attach),
786 DEVMETHOD(device_resume, xencons_resume),
791 static driver_t xencons_driver = {
797 DRIVER_MODULE(xc, xenpv, xencons_driver, xencons_devclass, 0, 0);