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