xref: /netbsd-src/sys/arch/xen/xen/xencons.c (revision f34c02f1ad699a27184a0204ea2c2b0d15637e0e)
1 /*	$NetBSD: xencons.c,v 1.53 2023/02/25 00:35:40 riastradh Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Manuel Bouyer.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 /*
29  *
30  * Copyright (c) 2004 Christian Limpach.
31  * All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  */
53 
54 
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: xencons.c,v 1.53 2023/02/25 00:35:40 riastradh Exp $");
57 
58 #include "opt_xen.h"
59 
60 #include <sys/param.h>
61 #include <sys/ioctl.h>
62 #include <sys/proc.h>
63 #include <sys/tty.h>
64 #include <sys/systm.h>
65 #include <sys/device.h>
66 #include <sys/conf.h>
67 #include <sys/kauth.h>
68 #include <sys/kernel.h>
69 
70 #include <xen/intr.h>
71 #include <xen/xen.h>
72 #include <xen/hypervisor.h>
73 #include <xen/evtchn.h>
74 #include <uvm/uvm.h>
75 #include <machine/pmap.h>
76 #include <xen/include/public/io/console.h>
77 
78 #include <dev/cons.h>
79 
80 #ifdef DDB
81 #include <ddb/db_output.h>	/* XXX for db_max_line */
82 #endif
83 
84 #undef XENDEBUG
85 
86 #ifdef XENDEBUG
87 #define XENPRINTK(x) printk x
88 #else
89 #define XENPRINTK(x)
90 #endif
91 
92 static int xencons_isconsole = 0;
93 static struct xencons_softc *xencons_console_device = NULL;
94 static struct intrhand *ih;
95 
96 #define	XENCONS_UNIT(x)	(minor(x))
97 #define XENCONS_BURST 128
98 
99 static int xencons_match(device_t, cfdata_t, void *);
100 static void xencons_attach(device_t, device_t, void *);
101 static int xencons_intr(void *);
102 static void xencons_tty_input(struct xencons_softc *, char*, int);
103 
104 struct xencons_softc {
105 	device_t sc_dev;
106 	struct	tty *sc_tty;
107 	int polling;
108 };
109 volatile struct xencons_interface *xencons_interface;
110 
111 CFATTACH_DECL_NEW(xencons, sizeof(struct xencons_softc),
112     xencons_match, xencons_attach, NULL, NULL);
113 
114 extern struct cfdriver xencons_cd;
115 
116 static dev_type_open(xencons_open);
117 static dev_type_close(xencons_close);
118 static dev_type_read(xencons_read);
119 static dev_type_write(xencons_write);
120 static dev_type_ioctl(xencons_ioctl);
121 static dev_type_stop(xencons_stop);
122 static dev_type_tty(xencons_tty);
123 static dev_type_poll(xencons_poll);
124 
125 const struct cdevsw xencons_cdevsw = {
126 	.d_open = xencons_open,
127 	.d_close = xencons_close,
128 	.d_read = xencons_read,
129 	.d_write = xencons_write,
130 	.d_ioctl = xencons_ioctl,
131 	.d_stop = xencons_stop,
132 	.d_tty = xencons_tty,
133 	.d_poll = xencons_poll,
134 	.d_mmap = NULL,	/* XXX: is this safe? - dholland 20140315 */
135 	.d_kqfilter = ttykqfilter,
136 	.d_discard = nodiscard,
137 	.d_flag = D_TTY
138 };
139 
140 static int xencons_handler(void *);
141 static int xenconscn_getc(dev_t);
142 static void xenconscn_putc(dev_t, int);
143 static void xenconscn_pollc(dev_t, int);
144 
145 static bool xencons_suspend(device_t, const pmf_qual_t *);
146 static bool xencons_resume(device_t, const pmf_qual_t *);
147 
148 static struct consdev xencons = {
149 	NULL, NULL, xenconscn_getc, xenconscn_putc, xenconscn_pollc,
150 	NULL, NULL, NULL, NODEV, CN_NORMAL
151 };
152 
153 static struct cnm_state xencons_cnm_state;
154 
155 static void xencons_start(struct tty *);
156 static int xencons_param(struct tty *, struct termios *);
157 
158 static int
xencons_match(device_t parent,cfdata_t match,void * aux)159 xencons_match(device_t parent, cfdata_t match, void *aux)
160 {
161 	struct xencons_attach_args *xa = (struct xencons_attach_args *)aux;
162 
163 	if (strcmp(xa->xa_device, "xencons") == 0)
164 		return 1;
165 	return 0;
166 }
167 
168 static void
xencons_attach(device_t parent,device_t self,void * aux)169 xencons_attach(device_t parent, device_t self, void *aux)
170 {
171 	struct xencons_softc *sc = device_private(self);
172 
173 	aprint_normal(": Xen Virtual Console Driver\n");
174 
175 	sc->sc_dev = self;
176 	sc->sc_tty = tty_alloc();
177 	tty_attach(sc->sc_tty);
178 	sc->sc_tty->t_oproc = xencons_start;
179 	sc->sc_tty->t_param = xencons_param;
180 
181 	if (xencons_isconsole) {
182 		int maj;
183 
184 		/* Locate the major number. */
185 		maj = cdevsw_lookup_major(&xencons_cdevsw);
186 
187 		/* There can be only one, but it can have any unit number. */
188 		cn_tab->cn_dev = makedev(maj, device_unit(self));
189 
190 		aprint_verbose_dev(self, "console major %d, unit %d\n",
191 		    maj, device_unit(self));
192 
193 		sc->sc_tty->t_dev = cn_tab->cn_dev;
194 
195 #ifdef DDB
196 		/* Set db_max_line to avoid paging. */
197 		db_max_line = 0x7fffffff;
198 #endif
199 
200 		xencons_console_device = sc;
201 
202 		xencons_resume(self, PMF_Q_NONE);
203 	}
204 	sc->polling = 0;
205 
206 	if (!pmf_device_register(self, xencons_suspend, xencons_resume))
207 		aprint_error_dev(self, "couldn't establish power handler\n");
208 }
209 
210 static bool
xencons_suspend(device_t dev,const pmf_qual_t * qual)211 xencons_suspend(device_t dev, const pmf_qual_t *qual) {
212 
213 	int evtch;
214 
215 	/* dom0 console should not be suspended */
216 	if (!xendomain_is_dom0()) {
217 		evtch = xen_start_info.console_evtchn;
218 		hypervisor_mask_event(evtch);
219 		xen_intr_disestablish(ih);
220 		aprint_verbose_dev(dev, "removed event channel %d\n", ih->ih_pin);
221 	}
222 
223 	return true;
224 }
225 
226 static bool
xencons_resume(device_t dev,const pmf_qual_t * qual)227 xencons_resume(device_t dev, const pmf_qual_t *qual) {
228 
229 	int evtch = -1;
230 
231 	if (xendomain_is_dom0()) {
232 		/* dom0 console resume is required only during first start-up */
233 		if (cold) {
234 			evtch = bind_virq_to_evtch(VIRQ_CONSOLE);
235 			ih = xen_intr_establish_xname(-1, &xen_pic, evtch,
236 			    IST_LEVEL, IPL_TTY, xencons_intr,
237 			    xencons_console_device, false,
238 			    device_xname(dev));
239 			KASSERT(ih != NULL);
240 		}
241 	} else {
242 		evtch = xen_start_info.console_evtchn;
243 		ih = xen_intr_establish_xname(-1, &xen_pic, evtch,
244 		    IST_LEVEL, IPL_TTY, xencons_handler,
245 		    xencons_console_device, false, device_xname(dev));
246 		KASSERT(ih != NULL);
247 	}
248 
249 	if (evtch != -1) {
250 		aprint_verbose_dev(dev, "using event channel %d\n", evtch);
251 		hypervisor_unmask_event(evtch);
252 	}
253 
254 	return true;
255 }
256 
257 static int
xencons_open(dev_t dev,int flag,int mode,struct lwp * l)258 xencons_open(dev_t dev, int flag, int mode, struct lwp *l)
259 {
260 	struct xencons_softc *sc;
261 	struct tty *tp;
262 
263 	sc = device_lookup_private(&xencons_cd, XENCONS_UNIT(dev));
264 	if (sc == NULL)
265 		return (ENXIO);
266 
267 	tp = sc->sc_tty;
268 
269 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
270 		return (EBUSY);
271 
272 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
273 		tp->t_dev = dev;
274 		ttychars(tp);
275 		tp->t_iflag = TTYDEF_IFLAG;
276 		tp->t_oflag = TTYDEF_OFLAG;
277 		tp->t_cflag = TTYDEF_CFLAG;
278 		tp->t_lflag = TTYDEF_LFLAG;
279 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
280 		xencons_param(tp, &tp->t_termios);
281 		ttsetwater(tp);
282 	}
283 	tp->t_state |= TS_CARR_ON;
284 
285 	return ((*tp->t_linesw->l_open)(dev, tp));
286 }
287 
288 static int
xencons_close(dev_t dev,int flag,int mode,struct lwp * l)289 xencons_close(dev_t dev, int flag, int mode, struct lwp *l)
290 {
291 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
292 	    XENCONS_UNIT(dev));
293 	struct tty *tp = sc->sc_tty;
294 
295 	if (tp == NULL)
296 		return (0);
297 	(*tp->t_linesw->l_close)(tp, flag);
298 	ttyclose(tp);
299 #ifdef notyet /* XXX */
300 	tty_free(tp);
301 #endif
302 	return (0);
303 }
304 
305 static int
xencons_read(dev_t dev,struct uio * uio,int flag)306 xencons_read(dev_t dev, struct uio *uio, int flag)
307 {
308 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
309 	    XENCONS_UNIT(dev));
310 	struct tty *tp = sc->sc_tty;
311 
312 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
313 }
314 
315 static int
xencons_write(dev_t dev,struct uio * uio,int flag)316 xencons_write(dev_t dev, struct uio *uio, int flag)
317 {
318 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
319 	    XENCONS_UNIT(dev));
320 	struct tty *tp = sc->sc_tty;
321 
322 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
323 }
324 
325 static int
xencons_poll(dev_t dev,int events,struct lwp * l)326 xencons_poll(dev_t dev, int events, struct lwp *l)
327 {
328 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
329 	    XENCONS_UNIT(dev));
330 	struct tty *tp = sc->sc_tty;
331 
332 	return ((*tp->t_linesw->l_poll)(tp, events, l));
333 }
334 
335 static struct tty *
xencons_tty(dev_t dev)336 xencons_tty(dev_t dev)
337 {
338 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
339 	    XENCONS_UNIT(dev));
340 	struct tty *tp = sc->sc_tty;
341 
342 	return (tp);
343 }
344 
345 static int
xencons_ioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)346 xencons_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
347 {
348 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
349 	    XENCONS_UNIT(dev));
350 	struct tty *tp = sc->sc_tty;
351 	int error;
352 
353 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
354 	if (error != EPASSTHROUGH)
355 		return (error);
356 
357 	error = ttioctl(tp, cmd, data, flag, l);
358 	if (error != EPASSTHROUGH)
359 		return (error);
360 
361 	switch (cmd) {
362 	default:
363 		return (EPASSTHROUGH);
364 	}
365 
366 #ifdef DIAGNOSTIC
367 	panic("xencons_ioctl: impossible");
368 #endif
369 }
370 
371 static void
xencons_start(struct tty * tp)372 xencons_start(struct tty *tp)
373 {
374 	struct clist *cl;
375 	int s;
376 
377 	s = spltty();
378 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
379 		goto out;
380 	tp->t_state |= TS_BUSY;
381 	splx(s);
382 
383 	/*
384 	 * We need to do this outside spl since it could be fairly
385 	 * expensive and we don't want our serial ports to overflow.
386 	 */
387 	cl = &tp->t_outq;
388 	if (xendomain_is_dom0()) {
389 		int len, r;
390 		u_char buf[XENCONS_BURST+1];
391 
392 		len = q_to_b(cl, buf, XENCONS_BURST);
393 		while (len > 0) {
394 			r = HYPERVISOR_console_io(CONSOLEIO_write, len, buf);
395 			if (r <= 0)
396 				break;
397 			len -= r;
398 		}
399 	} else {
400 		XENCONS_RING_IDX cons, prod, len;
401 
402 #define XNC_OUT (xencons_interface->out)
403 		cons = xencons_interface->out_cons;
404 		prod = xencons_interface->out_prod;
405 		xen_rmb();
406 		while (prod != cons + sizeof(xencons_interface->out)) {
407 			if (MASK_XENCONS_IDX(prod, XNC_OUT) <
408 			    MASK_XENCONS_IDX(cons, XNC_OUT)) {
409 				len = MASK_XENCONS_IDX(cons, XNC_OUT) -
410 				    MASK_XENCONS_IDX(prod, XNC_OUT);
411 			} else {
412 				len = sizeof(XNC_OUT) -
413 				    MASK_XENCONS_IDX(prod, XNC_OUT);
414 			}
415 			len = q_to_b(cl, __UNVOLATILE(
416 			    &XNC_OUT[MASK_XENCONS_IDX(prod, XNC_OUT)]), len);
417 			if (len == 0)
418 				break;
419 			prod = prod + len;
420 		}
421 		xen_wmb();
422 		xencons_interface->out_prod = prod;
423 		xen_wmb();
424 		hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
425 #undef XNC_OUT
426 	}
427 
428 	s = spltty();
429 	tp->t_state &= ~TS_BUSY;
430 	if (ttypull(tp)) {
431 		tp->t_state |= TS_TIMEOUT;
432 		callout_schedule(&tp->t_rstrt_ch, 1);
433 	}
434 out:
435 	splx(s);
436 }
437 
438 static void
xencons_stop(struct tty * tp,int flag)439 xencons_stop(struct tty *tp, int flag)
440 {
441 
442 }
443 
444 /* Non-privileged console interrupt routine */
445 static int
xencons_handler(void * arg)446 xencons_handler(void *arg)
447 {
448 	struct xencons_softc *sc = arg;
449 	XENCONS_RING_IDX cons, prod, len;
450 	int s = spltty();
451 
452 	if (sc->polling) {
453 		splx(s);
454 		return 1;
455 	}
456 
457 
458 #define XNC_IN (xencons_interface->in)
459 
460 	cons = xencons_interface->in_cons;
461 	prod = xencons_interface->in_prod;
462 	xen_rmb();
463 	while (cons != prod) {
464 		if (MASK_XENCONS_IDX(cons, XNC_IN) <
465 		    MASK_XENCONS_IDX(prod, XNC_IN))
466 			len = MASK_XENCONS_IDX(prod, XNC_IN) -
467 			    MASK_XENCONS_IDX(cons, XNC_IN);
468 		else
469 			len = sizeof(XNC_IN) - MASK_XENCONS_IDX(cons, XNC_IN);
470 
471 		xencons_tty_input(sc, __UNVOLATILE(
472 		    &XNC_IN[MASK_XENCONS_IDX(cons, XNC_IN)]), len);
473 		if (__predict_false(xencons_interface->in_cons != cons)) {
474 			/* catch up with xenconscn_getc() */
475 			cons = xencons_interface->in_cons;
476 			prod = xencons_interface->in_prod;
477 			xen_rmb();
478 		} else {
479 			cons += len;
480 			xen_wmb();
481 			xencons_interface->in_cons = cons;
482 		}
483 	}
484 	xen_wmb();
485 	hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
486 	splx(s);
487 	return 1;
488 #undef XNC_IN
489 }
490 
491 static void
xencons_tty_input(struct xencons_softc * sc,char * buf,int len)492 xencons_tty_input(struct xencons_softc *sc, char* buf, int len)
493 {
494 	struct tty *tp;
495 	int i;
496 
497 	tp = sc->sc_tty;
498 	if (tp == NULL)
499 		return;
500 
501 	for (i = 0; i < len; i++) {
502 		cn_check_magic(sc->sc_tty->t_dev, buf[i], xencons_cnm_state);
503 		(*tp->t_linesw->l_rint)(buf[i], tp);
504 	}
505 }
506 
507 /* privileged receive callback */
508 static int
xencons_intr(void * p)509 xencons_intr(void *p)
510 {
511 	static char rbuf[16];
512 	int len;
513 	struct xencons_softc *sc = p;
514 
515 	if (sc == NULL)
516 		/* Interrupt may happen during resume */
517 		return 1;
518 
519 	if (sc->polling)
520 		return 1;
521 
522 	while ((len =
523 	    HYPERVISOR_console_io(CONSOLEIO_read, sizeof(rbuf), rbuf)) > 0) {
524 		xencons_tty_input(sc, rbuf, len);
525 	}
526 	return 1;
527 }
528 
529 void
xenconscn_attach(void)530 xenconscn_attach(void)
531 {
532 
533 	cn_tab = &xencons;
534 
535 	/* console ring mapped in locore.S */
536 
537 	cn_init_magic(&xencons_cnm_state);
538 	cn_set_magic("+++++");
539 
540 	xencons_isconsole = 1;
541 }
542 
543 static int
xenconscn_getc(dev_t dev)544 xenconscn_getc(dev_t dev)
545 {
546 	char c;
547 	int s = spltty();
548 	XENCONS_RING_IDX cons, prod;
549 
550 	if (xencons_console_device && xencons_console_device->polling == 0) {
551 		printf("xenconscn_getc() but not polling\n");
552 		splx(s);
553 		return 0;
554 	}
555 	if (xendomain_is_dom0()) {
556 		while (HYPERVISOR_console_io(CONSOLEIO_read, 1, &c) == 0)
557 			;
558 		cn_check_magic(dev, c, xencons_cnm_state);
559 		splx(s);
560 		return c;
561 	}
562 	if (xencons_console_device == NULL) {
563 		printf("xenconscn_getc(): not console\n");
564 		while (1)
565 			;  /* loop here instead of in ddb */
566 		splx(s);
567 		return 0;
568 	}
569 
570 	if (xencons_console_device->polling == 0) {
571 		printf("xenconscn_getc() but not polling\n");
572 		splx(s);
573 		return 0;
574 	}
575 
576 	cons = xencons_interface->in_cons;
577 	prod = xencons_interface->in_prod;
578 	while (cons == prod) {
579 		HYPERVISOR_yield();
580 		prod = xencons_interface->in_prod;
581 	}
582 	xen_rmb();
583 	c = xencons_interface->in[MASK_XENCONS_IDX(xencons_interface->in_cons,
584 	    xencons_interface->in)];
585 	xen_wmb();
586 	xencons_interface->in_cons = cons + 1;
587 	cn_check_magic(dev, c, xencons_cnm_state);
588 	splx(s);
589 	return c;
590 }
591 
592 static void
xenconscn_putc(dev_t dev,int c)593 xenconscn_putc(dev_t dev, int c)
594 {
595 	int s = spltty();
596 	XENCONS_RING_IDX cons, prod;
597 
598 	if (xendomain_is_dom0()) {
599 		u_char buf[1];
600 
601 		buf[0] = c;
602 		(void)HYPERVISOR_console_io(CONSOLEIO_write, 1, buf);
603 	} else {
604 		XENPRINTK(("xenconscn_putc(%c)\n", c));
605 
606 		cons = xencons_interface->out_cons;
607 		prod = xencons_interface->out_prod;
608 		xen_rmb();
609 		while (prod == cons + sizeof(xencons_interface->out)) {
610 			cons = xencons_interface->out_cons;
611 			prod = xencons_interface->out_prod;
612 			xen_rmb();
613 		}
614 		xencons_interface->out[MASK_XENCONS_IDX(xencons_interface->out_prod,
615 		    xencons_interface->out)] = c;
616 		xen_wmb();
617 		xencons_interface->out_prod++;
618 		xen_wmb();
619 		hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
620 		splx(s);
621 	}
622 }
623 
624 static void
xenconscn_pollc(dev_t dev,int on)625 xenconscn_pollc(dev_t dev, int on)
626 {
627 	if (xencons_console_device)
628 		xencons_console_device->polling = on;
629 }
630 
631 /*
632  * Set line parameters.
633  */
634 static int
xencons_param(struct tty * tp,struct termios * t)635 xencons_param(struct tty *tp, struct termios *t)
636 {
637 
638 	tp->t_ispeed = t->c_ispeed;
639 	tp->t_ospeed = t->c_ospeed;
640 	tp->t_cflag = t->c_cflag;
641 	return (0);
642 }
643