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
66static char driver_name[] = "xc";
67
68struct xencons_priv;
69
70typedef void xencons_early_init_t(struct xencons_priv *cons);
71typedef int xencons_init_t(device_t dev, struct tty *tp,
72    driver_intr_t intr_handler);
73typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
74    unsigned int size);
75typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
76    unsigned int size);
77
78struct 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
91struct 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 */
133static struct xencons_priv main_cons;
134
135#define XC_POLLTIME 	(hz/10)
136
137/*----------------------------- Debug function ------------------------------*/
138struct putchar_arg {
139	char	*buf;
140	size_t	size;
141	size_t	n_next;
142};
143
144static void
145putchar(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
167void
168xc_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 */
200static inline void xencons_lock(struct xencons_priv *cons)
201{
202
203	if (!KERNEL_PANICKED())
204		mtx_lock_spin(&cons->mtx);
205
206}
207
208static 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 ---------------------*/
218static void
219xencons_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
227static int
228xencons_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
244static int
245xencons_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
254static int
255xencons_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
264static 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 ---------------------------*/
272static void
273xencons_early_init_ring(struct xencons_priv *cons)
274{
275	cons->intf = pmap_mapdev_attr(ptoa(xen_get_console_mfn()), PAGE_SIZE,
276	    PAT_WRITE_BACK);
277	cons->evtchn = xen_get_console_evtchn();
278}
279
280static int
281xencons_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
299static void
300xencons_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
318static int
319xencons_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
351static int
352xencons_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
382static 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 */
396static void
397xencons_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 */
414static void
415xencons_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 */
431static bool
432xencons_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
443static void
444xencons_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
476static bool
477xencons_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
490static int
491xencons_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
509static bool
510xencons_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
534static void
535xencons_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 */
576static void
577xencons_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 ---------------------------*/
587static void
588xencons_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
598static void
599xencons_cninit(struct consdev *cp)
600{
601
602	xencons_early_init();
603}
604
605static void
606xencons_cnterm(struct consdev *cp)
607{
608}
609
610static void
611xencons_cngrab(struct consdev *cp)
612{
613}
614
615static void
616xencons_cnungrab(struct consdev *cp)
617{
618}
619
620static int
621xencons_cngetc(struct consdev *dev)
622{
623
624	xencons_rx(&main_cons);
625
626	return (xencons_getc(&main_cons));
627}
628
629static void
630xencons_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
639CONSOLE_DRIVER(xencons);
640
641/*----------------------------- TTY driver ---------------------------------*/
642
643static int
644xencons_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
655static void
656xencons_tty_close(struct tty *tp)
657{
658	struct xencons_priv *cons;
659
660	cons = tty_softc(tp);
661
662	cons->opened = false;
663}
664
665static void
666xencons_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
679static void
680xencons_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
693static 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 ------------------------------*/
701static void
702xencons_identify(driver_t *driver, device_t parent)
703{
704	device_t child;
705
706	if (main_cons.ops == NULL)
707		return;
708
709	child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
710}
711
712static int
713xencons_probe(device_t dev)
714{
715
716	device_set_desc(dev, "Xen Console");
717	return (BUS_PROBE_NOWILDCARD);
718}
719
720static int
721xencons_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
754static int
755xencons_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
774static devclass_t xencons_devclass;
775
776static 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
785static driver_t xencons_driver = {
786	driver_name,
787	xencons_methods,
788	0,
789};
790
791DRIVER_MODULE(xc, xenpv, xencons_driver, xencons_devclass, 0, 0);
792