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