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