xref: /freebsd/sys/dev/xen/console/xen_console.c (revision a25896ca1270e25b657ceaa8d47d5699515f5c25)
1 /*
2  * Copyright (c) 2015 Julien Grall <julien.grall@citrix.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/module.h>
32 #include <sys/systm.h>
33 #include <sys/consio.h>
34 #include <sys/priv.h>
35 #include <sys/proc.h>
36 #include <sys/uio.h>
37 #include <sys/tty.h>
38 #include <sys/systm.h>
39 #include <sys/taskqueue.h>
40 #include <sys/conf.h>
41 #include <sys/kernel.h>
42 #include <sys/bus.h>
43 #include <sys/cons.h>
44 #include <sys/kdb.h>
45 #include <sys/proc.h>
46 
47 #include <machine/stdarg.h>
48 
49 #include <vm/vm.h>
50 #include <vm/pmap.h>
51 
52 #include <xen/xen-os.h>
53 #include <xen/hypervisor.h>
54 #include <xen/xen_intr.h>
55 #include <xen/interface/io/console.h>
56 
57 #include "opt_ddb.h"
58 #include "opt_printf.h"
59 
60 #ifdef DDB
61 #include <ddb/ddb.h>
62 #endif
63 
64 static char driver_name[] = "xc";
65 
66 struct xencons_priv;
67 
68 typedef void xencons_early_init_t(struct xencons_priv *cons);
69 typedef int xencons_init_t(device_t dev, struct tty *tp,
70     driver_intr_t intr_handler);
71 typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
72     unsigned int size);
73 typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
74     unsigned int size);
75 
76 struct xencons_ops {
77 	/*
78 	 * Called by the low-level driver during early boot.
79 	 * Only the minimal set up to get a console should be done here.
80 	 */
81 	xencons_early_init_t	*early_init;
82 	/* Prepare the console to be fully use */
83 	xencons_init_t		*init;
84 	/* Read/write helpers */
85 	xencons_read_t		*read;
86 	xencons_write_t		*write;
87 };
88 
89 struct xencons_priv {
90 	/* Mutex to protect the shared ring and the internal buffers */
91 	struct mtx			mtx;
92 	/* Interrupt handler used for notify the backend */
93 	xen_intr_handle_t		intr_handle;
94 	/* KDB internal state */
95 #ifdef KDB
96 	int				altbrk;
97 #endif
98 	/* Status of the tty */
99 	bool				opened;
100 	/* Callout used when the write buffer is full */
101 	struct callout			callout;
102 
103 	/* Internal buffers must be used with mtx locked */
104 #define WBUF_SIZE     4096
105 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
106 	char				wbuf[WBUF_SIZE];
107 	unsigned int			wc, wp; /* Consumer/producer wbuf */
108 
109 #define RBUF_SIZE     1024
110 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
111 	char				rbuf[RBUF_SIZE];
112 	unsigned int			rc, rp; /* Consumer/producer rbuf */
113 
114 	/* Pointer to the console operations */
115 	const struct xencons_ops	*ops;
116 
117 	/*
118 	 * Ring specific fields
119 	 * XXX: make an union?
120 	 */
121 	/* Event channel number for early notification (PV only) */
122 	uint32_t			evtchn;
123 	/* Console shared page */
124 	struct xencons_interface	*intf;
125 };
126 
127 /*
128  * Data for the main console
129  * Necessary to support low-level console driver
130  */
131 static struct xencons_priv main_cons;
132 
133 #define XC_POLLTIME 	(hz/10)
134 
135 /*----------------------------- Debug function ------------------------------*/
136 struct putchar_arg {
137 	char	*buf;
138 	size_t	size;
139 	size_t	n_next;
140 };
141 
142 static void
143 putchar(int c, void *arg)
144 {
145 	struct putchar_arg *pca;
146 
147 	pca = (struct putchar_arg *)arg;
148 
149 	if (pca->buf == NULL) {
150 		/*
151 		 * We have no buffer, output directly to the
152 		 * console char by char.
153 		 */
154 		HYPERVISOR_console_write((char *)&c, 1);
155 	} else {
156 		pca->buf[pca->n_next++] = c;
157 		if ((pca->size == pca->n_next) || (c = '\0')) {
158 			/* Flush the buffer */
159 			HYPERVISOR_console_write(pca->buf, pca->n_next);
160 			pca->n_next = 0;
161 		}
162 	}
163 }
164 
165 void
166 xc_printf(const char *fmt, ...)
167 {
168 	va_list ap;
169 	struct putchar_arg pca;
170 #ifdef PRINTF_BUFR_SIZE
171 	char buf[PRINTF_BUFR_SIZE];
172 
173 	pca.buf = buf;
174 	pca.size = sizeof(buf);
175 	pca.n_next = 0;
176 #else
177 	pca.buf = NULL;
178 	pca.size = 0;
179 #endif
180 
181 	KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
182 
183 	va_start(ap, fmt);
184 	kvprintf(fmt, putchar, &pca, 10, ap);
185 	va_end(ap);
186 
187 #ifdef PRINTF_BUFR_SIZE
188 	if (pca.n_next != 0)
189 		HYPERVISOR_console_write(buf, pca.n_next);
190 #endif
191 }
192 
193 /*---------------------- Helpers for the console lock -----------------------*/
194 /*
195  * The lock is not used when the kernel is panicing as it will never recover
196  * and we want to output no matter what it costs.
197  */
198 static inline void xencons_lock(struct xencons_priv *cons)
199 {
200 
201 	if (panicstr == NULL)
202 		mtx_lock_spin(&cons->mtx);
203 
204 }
205 
206 static inline void xencons_unlock(struct xencons_priv *cons)
207 {
208 
209 	if (panicstr == NULL)
210 		mtx_unlock_spin(&cons->mtx);
211 }
212 
213 #define xencons_lock_assert(cons)	mtx_assert(&(cons)->mtx, MA_OWNED)
214 
215 /*------------------ Helpers for the hypervisor console ---------------------*/
216 static void
217 xencons_early_init_hypervisor(struct xencons_priv *cons)
218 {
219 	/*
220 	 * Nothing to setup for the low-level console when using
221 	 * the hypervisor console.
222 	 */
223 }
224 
225 static int
226 xencons_init_hypervisor(device_t dev, struct tty *tp,
227     driver_intr_t intr_handler)
228 {
229 	struct xencons_priv *cons;
230 	int err;
231 
232 	cons = tty_softc(tp);
233 
234 	err = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
235 	    intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
236 	if (err != 0)
237 		device_printf(dev, "Can't register console interrupt\n");
238 
239 	return (err);
240 }
241 
242 static int
243 xencons_write_hypervisor(struct xencons_priv *cons, const char *buffer,
244     unsigned int size)
245 {
246 
247 	HYPERVISOR_console_io(CONSOLEIO_write, size, buffer);
248 
249 	return (size);
250 }
251 
252 static int
253 xencons_read_hypervisor(struct xencons_priv *cons, char *buffer,
254     unsigned int size)
255 {
256 
257 	xencons_lock_assert(cons);
258 
259 	return (HYPERVISOR_console_io(CONSOLEIO_read, size, buffer));
260 }
261 
262 static const struct xencons_ops xencons_hypervisor_ops = {
263 	.early_init	= xencons_early_init_hypervisor,
264 	.init		= xencons_init_hypervisor,
265 	.read		= xencons_read_hypervisor,
266 	.write		= xencons_write_hypervisor,
267 };
268 
269 /*------------------ Helpers for the ring console ---------------------------*/
270 static void
271 xencons_early_init_ring(struct xencons_priv *cons)
272 {
273 	cons->intf = pmap_mapdev_attr(ptoa(xen_get_console_mfn()), PAGE_SIZE,
274 	    PAT_WRITE_BACK);
275 	cons->evtchn = xen_get_console_evtchn();
276 }
277 
278 static int
279 xencons_init_ring(device_t dev, struct tty *tp, driver_intr_t intr_handler)
280 {
281 	struct xencons_priv *cons;
282 	int err;
283 
284 	cons = tty_softc(tp);
285 
286 	if (cons->evtchn == 0)
287 		return (ENODEV);
288 
289 	err = xen_intr_bind_local_port(dev, cons->evtchn, NULL,
290 	    intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
291 	if (err != 0)
292 		return (err);
293 
294 	return (0);
295 }
296 
297 static void
298 xencons_notify_ring(struct xencons_priv *cons)
299 {
300 	/*
301 	 * The console may be used before the ring interrupt is properly
302 	 * initialized.
303 	 * If so, fallback to directly use the event channel hypercall.
304 	 */
305 	if (__predict_true(cons->intr_handle != NULL))
306 		xen_intr_signal(cons->intr_handle);
307 	else {
308 		struct evtchn_send send = {
309 			.port = cons->evtchn
310 		};
311 
312 		HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
313 	}
314 }
315 
316 static int
317 xencons_write_ring(struct xencons_priv *cons, const char *buffer,
318     unsigned int size)
319 {
320 	struct xencons_interface *intf;
321 	XENCONS_RING_IDX wcons, wprod;
322 	int sent;
323 
324 	intf = cons->intf;
325 
326 	xencons_lock_assert(cons);
327 
328 	wcons = intf->out_cons;
329 	wprod = intf->out_prod;
330 
331 	mb();
332 	KASSERT((wprod - wcons) <= sizeof(intf->out),
333 		("console send ring inconsistent"));
334 
335 	for (sent = 0; sent < size; sent++, wprod++) {
336 		if ((wprod - wcons) >= sizeof(intf->out))
337 			break;
338 		intf->out[MASK_XENCONS_IDX(wprod, intf->out)] = buffer[sent];
339 	}
340 
341 	wmb();
342 	intf->out_prod = wprod;
343 
344 	xencons_notify_ring(cons);
345 
346 	return (sent);
347 }
348 
349 static int
350 xencons_read_ring(struct xencons_priv *cons, char *buffer, unsigned int size)
351 {
352 	struct xencons_interface *intf;
353 	XENCONS_RING_IDX rcons, rprod;
354 	unsigned int rsz;
355 
356 	intf = cons->intf;
357 
358 	xencons_lock_assert(cons);
359 
360 	rcons = intf->in_cons;
361 	rprod = intf->in_prod;
362 	rmb();
363 
364 	for (rsz = 0; rsz < size; rsz++, rcons++) {
365 		if (rprod == rcons)
366 			break;
367 		buffer[rsz] = intf->in[MASK_XENCONS_IDX(rcons, intf->in)];
368 	}
369 
370 	wmb();
371 	intf->in_cons = rcons;
372 
373 	/* No need to notify the backend if nothing has been read */
374 	if (rsz != 0)
375 		xencons_notify_ring(cons);
376 
377 	return (rsz);
378 }
379 
380 static const struct xencons_ops xencons_ring_ops = {
381 	.early_init	= xencons_early_init_ring,
382 	.init		= xencons_init_ring,
383 	.read		= xencons_read_ring,
384 	.write		= xencons_write_ring,
385 };
386 
387 /*------------------ Common implementation of the console -------------------*/
388 
389 /*
390  * Called by the low-level driver during early boot to initialize the
391  * main console driver.
392  * Only the minimal set up to get a console should be done here.
393  */
394 static void
395 xencons_early_init(void)
396 {
397 
398 	mtx_init(&main_cons.mtx, "XCONS LOCK", NULL, MTX_SPIN);
399 
400 	if (xen_get_console_evtchn() == 0)
401 		main_cons.ops = &xencons_hypervisor_ops;
402 	else
403 		main_cons.ops = &xencons_ring_ops;
404 
405 	main_cons.ops->early_init(&main_cons);
406 }
407 
408 /*
409  * Receive character from the console and put them in the internal buffer
410  * XXX: Handle overflow of the internal buffer
411  */
412 static void
413 xencons_rx(struct xencons_priv *cons)
414 {
415 	char buf[16];
416 	int sz;
417 
418 	xencons_lock(cons);
419 	while ((sz = cons->ops->read(cons, buf, sizeof(buf))) > 0) {
420 		int i;
421 
422 		for (i = 0; i < sz; i++)
423 			cons->rbuf[RBUF_MASK(cons->rp++)] = buf[i];
424 	}
425 	xencons_unlock(cons);
426 }
427 
428 /* Return true if the write buffer is full */
429 static bool
430 xencons_tx_full(struct xencons_priv *cons)
431 {
432 	unsigned int used;
433 
434 	xencons_lock(cons);
435 	used = cons->wp - cons->wc;
436 	xencons_unlock(cons);
437 
438 	return (used >= WBUF_SIZE);
439 }
440 
441 static void
442 xencons_tx_flush(struct xencons_priv *cons, int force)
443 {
444 	int        sz;
445 
446 	xencons_lock(cons);
447 	while (cons->wc != cons->wp) {
448 		int sent;
449 		sz = cons->wp - cons->wc;
450 		if (sz > (WBUF_SIZE - WBUF_MASK(cons->wc)))
451 			sz = WBUF_SIZE - WBUF_MASK(cons->wc);
452 		sent = cons->ops->write(cons, &cons->wbuf[WBUF_MASK(cons->wc)],
453 		    sz);
454 
455 		/*
456 		 * The other end may not have been initialized. Ignore
457 		 * the force.
458 		 */
459 		if (__predict_false(sent < 0))
460 			break;
461 
462 		/*
463 		 * If force is set, spin until the console data is
464 		 * flushed through the domain controller.
465 		 */
466 		if (sent == 0 && __predict_true(!force))
467 			break;
468 
469 		cons->wc += sent;
470 	}
471 	xencons_unlock(cons);
472 }
473 
474 static bool
475 xencons_putc(struct xencons_priv *cons, int c, bool force_flush)
476 {
477 
478 	xencons_lock(cons);
479 	if ((cons->wp - cons->wc) < WBUF_SIZE)
480 		cons->wbuf[WBUF_MASK(cons->wp++)] = c;
481 	xencons_unlock(cons);
482 
483 	xencons_tx_flush(cons, force_flush);
484 
485 	return (xencons_tx_full(cons));
486 }
487 
488 static int
489 xencons_getc(struct xencons_priv *cons)
490 {
491 	int ret;
492 
493 	xencons_lock(cons);
494 	if (cons->rp != cons->rc) {
495 		/* We need to return only one char */
496 		ret = (int)cons->rbuf[RBUF_MASK(cons->rc)];
497 		cons->rc++;
498 	} else {
499 		ret = -1;
500 	}
501 
502 	xencons_unlock(cons);
503 
504 	return (ret);
505 }
506 
507 static bool
508 xencons_tx(struct tty *tp)
509 {
510 	bool cons_full;
511 	char c;
512 	struct xencons_priv *cons;
513 
514 	cons = tty_softc(tp);
515 
516 	tty_lock_assert(tp, MA_OWNED);
517 
518 	/*
519 	 * Don't transmit any character if the buffer is full. Otherwise,
520 	 * characters may be lost
521 	 */
522 	if (xencons_tx_full(cons))
523 		return (false);
524 
525 	cons_full = false;
526 	while (!cons_full && ttydisc_getc(tp, &c, 1) == 1)
527 		cons_full = xencons_putc(cons, c, false);
528 
529 	return (!cons_full);
530 }
531 
532 static void
533 xencons_intr(void *arg)
534 {
535 	struct tty *tp;
536 	struct xencons_priv *cons;
537 	int ret;
538 
539 	tp = arg;
540 	cons = tty_softc(tp);
541 
542 	/*
543 	 * The input will be used by the low-level console when KDB is active
544 	 */
545 	if (kdb_active)
546 		return;
547 
548 	/*
549 	 * It's not necessary to retrieve input when the tty is not opened
550 	 */
551 	if (!cons->opened)
552 		return;
553 
554 	xencons_rx(cons);
555 
556 	tty_lock(tp);
557 	while ((ret = xencons_getc(cons)) != -1) {
558 #ifdef KDB
559 		kdb_alt_break(ret, &cons->altbrk);
560 #endif
561 		ttydisc_rint(tp, ret, 0);
562 	}
563 	ttydisc_rint_done(tp);
564 	tty_unlock(tp);
565 
566 	/* Try to flush remaining characters if necessary */
567 	xencons_tx_flush(cons, 0);
568 }
569 
570 /*
571  * Helpers to call while shutting down:
572  *	- Force flush all output
573  */
574 static void
575 xencons_shutdown(void *arg, int howto)
576 {
577 	struct tty *tp;
578 
579 	tp = arg;
580 
581 	xencons_tx_flush(tty_softc(tp), 1);
582 }
583 
584 /*---------------------- Low-level console driver ---------------------------*/
585 static void
586 xencons_cnprobe(struct consdev *cp)
587 {
588 
589 	if (!xen_domain())
590 		return;
591 
592 	cp->cn_pri = CN_REMOTE;
593 	sprintf(cp->cn_name, "%s0", driver_name);
594 }
595 
596 static void
597 xencons_cninit(struct consdev *cp)
598 {
599 
600 	xencons_early_init();
601 }
602 
603 static void
604 xencons_cnterm(struct consdev *cp)
605 {
606 }
607 
608 static void
609 xencons_cngrab(struct consdev *cp)
610 {
611 }
612 
613 static void
614 xencons_cnungrab(struct consdev *cp)
615 {
616 }
617 
618 static int
619 xencons_cngetc(struct consdev *dev)
620 {
621 
622 	xencons_rx(&main_cons);
623 
624 	return (xencons_getc(&main_cons));
625 }
626 
627 static void
628 xencons_cnputc(struct consdev *dev, int c)
629 {
630 	/*
631 	 * The low-level console is used by KDB and panic. We have to ensure
632 	 * that any character sent will be seen by the backend.
633 	 */
634 	xencons_putc(&main_cons, c, true);
635 }
636 
637 CONSOLE_DRIVER(xencons);
638 
639 /*----------------------------- TTY driver ---------------------------------*/
640 
641 static int
642 xencons_tty_open(struct tty *tp)
643 {
644 	struct xencons_priv *cons;
645 
646 	cons = tty_softc(tp);
647 
648 	cons->opened = true;
649 
650 	return (0);
651 }
652 
653 static void
654 xencons_tty_close(struct tty *tp)
655 {
656 	struct xencons_priv *cons;
657 
658 	cons = tty_softc(tp);
659 
660 	cons->opened = false;
661 }
662 
663 static void
664 xencons_timeout(void *v)
665 {
666 	struct tty *tp;
667 	struct xencons_priv *cons;
668 
669 	tp = v;
670 	cons = tty_softc(tp);
671 
672 	if (!xencons_tx(tp))
673 		callout_reset(&cons->callout, XC_POLLTIME,
674 		    xencons_timeout, tp);
675 }
676 
677 static void
678 xencons_tty_outwakeup(struct tty *tp)
679 {
680 	struct xencons_priv *cons;
681 
682 	cons = tty_softc(tp);
683 
684 	callout_stop(&cons->callout);
685 
686 	if (!xencons_tx(tp))
687 		callout_reset(&cons->callout, XC_POLLTIME,
688 		    xencons_timeout, tp);
689 }
690 
691 static struct ttydevsw xencons_ttydevsw = {
692         .tsw_flags	= TF_NOPREFIX,
693         .tsw_open	= xencons_tty_open,
694         .tsw_close	= xencons_tty_close,
695         .tsw_outwakeup	= xencons_tty_outwakeup,
696 };
697 
698 /*------------------------ Main console driver ------------------------------*/
699 static void
700 xencons_identify(driver_t *driver, device_t parent)
701 {
702 	device_t child;
703 
704 	if (main_cons.ops == NULL)
705 		return;
706 
707 	child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
708 }
709 
710 static int
711 xencons_probe(device_t dev)
712 {
713 
714 	device_set_desc(dev, "Xen Console");
715 	return (BUS_PROBE_NOWILDCARD);
716 }
717 
718 static int
719 xencons_attach(device_t dev)
720 {
721 	struct tty *tp;
722 	/*
723 	 * The main console is already allocated statically in order to
724 	 * support low-level console
725 	 */
726 	struct xencons_priv *cons;
727 	int err;
728 
729 	cons = &main_cons;
730 
731 	tp = tty_alloc(&xencons_ttydevsw, cons);
732 	tty_makedev(tp, NULL, "%s%r", driver_name, 0);
733 	device_set_softc(dev, tp);
734 
735 	callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
736 
737 	err = cons->ops->init(dev, tp, xencons_intr);
738 	if (err != 0) {
739 		device_printf(dev, "Unable to initialize the console (%d)\n",
740 		    err);
741 		return (err);
742 	}
743 
744 	/* register handler to flush console on shutdown */
745 	if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
746 	    tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
747 		device_printf(dev, "shutdown event registration failed!\n");
748 
749 	return (0);
750 }
751 
752 static int
753 xencons_resume(device_t dev)
754 {
755 	struct xencons_priv *cons;
756 	struct tty *tp;
757 	int err;
758 
759 	tp = device_get_softc(dev);
760 	cons = tty_softc(tp);
761 	xen_intr_unbind(&cons->intr_handle);
762 
763 	err = cons->ops->init(dev, tp, xencons_intr);
764 	if (err != 0) {
765 		device_printf(dev, "Unable to resume the console (%d)\n", err);
766 		return (err);
767 	}
768 
769 	return (0);
770 }
771 
772 static devclass_t xencons_devclass;
773 
774 static device_method_t xencons_methods[] = {
775 	DEVMETHOD(device_identify, xencons_identify),
776 	DEVMETHOD(device_probe, xencons_probe),
777 	DEVMETHOD(device_attach, xencons_attach),
778 	DEVMETHOD(device_resume, xencons_resume),
779 
780 	DEVMETHOD_END
781 };
782 
783 static driver_t xencons_driver = {
784 	driver_name,
785 	xencons_methods,
786 	0,
787 };
788 
789 DRIVER_MODULE(xc, xenpv, xencons_driver, xencons_devclass, 0, 0);
790