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