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