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