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