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
63static char driver_name[] = "xc";
64
65struct xencons_priv;
66
67typedef void xencons_early_init_t(struct xencons_priv *cons);
68typedef int xencons_init_t(device_t dev, struct tty *tp,
69    driver_intr_t intr_handler);
70typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
71    unsigned int size);
72typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
73    unsigned int size);
74
75struct 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
88struct 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 */
130static struct xencons_priv main_cons;
131
132#define XC_POLLTIME 	(hz/10)
133
134/*----------------------------- Debug function ------------------------------*/
135struct putchar_arg {
136	char	*buf;
137	size_t	size;
138	size_t	n_next;
139};
140
141void __weak_symbol
142xen_emergency_print(const char *str, size_t size)
143{
144	KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
145	HYPERVISOR_console_write(str, size);
146}
147
148static void
149putchar(int c, void *arg)
150{
151	struct putchar_arg *pca;
152
153	pca = (struct putchar_arg *)arg;
154
155	if (pca->buf == NULL) {
156		/*
157		 * We have no buffer, output directly to the
158		 * console char by char.
159		 */
160		xen_emergency_print((char *)&c, 1);
161	} else {
162		pca->buf[pca->n_next++] = c;
163		if ((pca->size == pca->n_next) || (c = '\0')) {
164			/* Flush the buffer */
165			xen_emergency_print(pca->buf, pca->n_next);
166			pca->n_next = 0;
167		}
168	}
169}
170
171void
172xc_printf(const char *fmt, ...)
173{
174	va_list ap;
175	struct putchar_arg pca;
176#ifdef PRINTF_BUFR_SIZE
177	char buf[PRINTF_BUFR_SIZE];
178
179	pca.buf = buf;
180	pca.size = sizeof(buf);
181	pca.n_next = 0;
182#else
183	pca.buf = NULL;
184	pca.size = 0;
185#endif
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		xen_emergency_print(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 (!KERNEL_PANICKED())
206		mtx_lock_spin(&cons->mtx);
207
208}
209
210static inline void xencons_unlock(struct xencons_priv *cons)
211{
212
213	if (!KERNEL_PANICKED())
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	cons->intf = pmap_mapdev_attr(ptoa(xen_get_console_mfn()), PAGE_SIZE,
278	    VM_MEMATTR_XEN);
279	cons->evtchn = xen_get_console_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_get_console_evtchn() == 0)
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_assert_locked(tp);
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_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 __unused;
707
708	if (main_cons.ops == NULL)
709		return;
710
711	child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
712}
713
714static int
715xencons_probe(device_t dev)
716{
717
718	device_set_desc(dev, "Xen Console");
719	return (BUS_PROBE_NOWILDCARD);
720}
721
722static int
723xencons_attach(device_t dev)
724{
725	struct tty *tp;
726	/*
727	 * The main console is already allocated statically in order to
728	 * support low-level console
729	 */
730	struct xencons_priv *cons;
731	int err;
732
733	cons = &main_cons;
734
735	tp = tty_alloc(&xencons_ttydevsw, cons);
736	tty_makedev(tp, NULL, "%s%r", driver_name, 0);
737	device_set_softc(dev, tp);
738
739	callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
740
741	err = cons->ops->init(dev, tp, xencons_intr);
742	if (err != 0) {
743		device_printf(dev, "Unable to initialize the console (%d)\n",
744		    err);
745		return (err);
746	}
747
748	/* register handler to flush console on shutdown */
749	if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
750	    tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
751		device_printf(dev, "shutdown event registration failed!\n");
752
753	return (0);
754}
755
756static int
757xencons_resume(device_t dev)
758{
759	struct xencons_priv *cons;
760	struct tty *tp;
761	int err;
762
763	tp = device_get_softc(dev);
764	cons = tty_softc(tp);
765	xen_intr_unbind(&cons->intr_handle);
766
767	err = cons->ops->init(dev, tp, xencons_intr);
768	if (err != 0) {
769		device_printf(dev, "Unable to resume the console (%d)\n", err);
770		return (err);
771	}
772
773	return (0);
774}
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, 0, 0);
792