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