linux/drivers/tty/hvc/hvc_xen.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * xen console driver interface to hvc_console.c
   4 *
   5 * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
   6 */
   7
   8#include <linux/console.h>
   9#include <linux/delay.h>
  10#include <linux/err.h>
  11#include <linux/irq.h>
  12#include <linux/init.h>
  13#include <linux/types.h>
  14#include <linux/list.h>
  15#include <linux/serial_core.h>
  16
  17#include <asm/io.h>
  18#include <asm/xen/hypervisor.h>
  19
  20#include <xen/xen.h>
  21#include <xen/interface/xen.h>
  22#include <xen/hvm.h>
  23#include <xen/grant_table.h>
  24#include <xen/page.h>
  25#include <xen/events.h>
  26#include <xen/interface/io/console.h>
  27#include <xen/interface/sched.h>
  28#include <xen/hvc-console.h>
  29#include <xen/xenbus.h>
  30
  31#include "hvc_console.h"
  32
  33#define HVC_COOKIE   0x58656e /* "Xen" in hex */
  34
  35struct xencons_info {
  36        struct list_head list;
  37        struct xenbus_device *xbdev;
  38        struct xencons_interface *intf;
  39        unsigned int evtchn;
  40        struct hvc_struct *hvc;
  41        int irq;
  42        int vtermno;
  43        grant_ref_t gntref;
  44};
  45
  46static LIST_HEAD(xenconsoles);
  47static DEFINE_SPINLOCK(xencons_lock);
  48
  49/* ------------------------------------------------------------------ */
  50
  51static struct xencons_info *vtermno_to_xencons(int vtermno)
  52{
  53        struct xencons_info *entry, *n, *ret = NULL;
  54
  55        if (list_empty(&xenconsoles))
  56                        return NULL;
  57
  58        list_for_each_entry_safe(entry, n, &xenconsoles, list) {
  59                if (entry->vtermno == vtermno) {
  60                        ret  = entry;
  61                        break;
  62                }
  63        }
  64
  65        return ret;
  66}
  67
  68static inline int xenbus_devid_to_vtermno(int devid)
  69{
  70        return devid + HVC_COOKIE;
  71}
  72
  73static inline void notify_daemon(struct xencons_info *cons)
  74{
  75        /* Use evtchn: this is called early, before irq is set up. */
  76        notify_remote_via_evtchn(cons->evtchn);
  77}
  78
  79static int __write_console(struct xencons_info *xencons,
  80                const char *data, int len)
  81{
  82        XENCONS_RING_IDX cons, prod;
  83        struct xencons_interface *intf = xencons->intf;
  84        int sent = 0;
  85
  86        cons = intf->out_cons;
  87        prod = intf->out_prod;
  88        mb();                   /* update queue values before going on */
  89
  90        if ((prod - cons) > sizeof(intf->out)) {
  91                pr_err_once("xencons: Illegal ring page indices");
  92                return -EINVAL;
  93        }
  94
  95        while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
  96                intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
  97
  98        wmb();                  /* write ring before updating pointer */
  99        intf->out_prod = prod;
 100
 101        if (sent)
 102                notify_daemon(xencons);
 103        return sent;
 104}
 105
 106static int domU_write_console(uint32_t vtermno, const char *data, int len)
 107{
 108        int ret = len;
 109        struct xencons_info *cons = vtermno_to_xencons(vtermno);
 110        if (cons == NULL)
 111                return -EINVAL;
 112
 113        /*
 114         * Make sure the whole buffer is emitted, polling if
 115         * necessary.  We don't ever want to rely on the hvc daemon
 116         * because the most interesting console output is when the
 117         * kernel is crippled.
 118         */
 119        while (len) {
 120                int sent = __write_console(cons, data, len);
 121
 122                if (sent < 0)
 123                        return sent;
 124
 125                data += sent;
 126                len -= sent;
 127
 128                if (unlikely(len))
 129                        HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
 130        }
 131
 132        return ret;
 133}
 134
 135static int domU_read_console(uint32_t vtermno, char *buf, int len)
 136{
 137        struct xencons_interface *intf;
 138        XENCONS_RING_IDX cons, prod;
 139        int recv = 0;
 140        struct xencons_info *xencons = vtermno_to_xencons(vtermno);
 141        if (xencons == NULL)
 142                return -EINVAL;
 143        intf = xencons->intf;
 144
 145        cons = intf->in_cons;
 146        prod = intf->in_prod;
 147        mb();                   /* get pointers before reading ring */
 148
 149        if ((prod - cons) > sizeof(intf->in)) {
 150                pr_err_once("xencons: Illegal ring page indices");
 151                return -EINVAL;
 152        }
 153
 154        while (cons != prod && recv < len)
 155                buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
 156
 157        mb();                   /* read ring before consuming */
 158        intf->in_cons = cons;
 159
 160        notify_daemon(xencons);
 161        return recv;
 162}
 163
 164static const struct hv_ops domU_hvc_ops = {
 165        .get_chars = domU_read_console,
 166        .put_chars = domU_write_console,
 167        .notifier_add = notifier_add_irq,
 168        .notifier_del = notifier_del_irq,
 169        .notifier_hangup = notifier_hangup_irq,
 170};
 171
 172static int dom0_read_console(uint32_t vtermno, char *buf, int len)
 173{
 174        return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
 175}
 176
 177/*
 178 * Either for a dom0 to write to the system console, or a domU with a
 179 * debug version of Xen
 180 */
 181static int dom0_write_console(uint32_t vtermno, const char *str, int len)
 182{
 183        int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
 184        if (rc < 0)
 185                return rc;
 186
 187        return len;
 188}
 189
 190static const struct hv_ops dom0_hvc_ops = {
 191        .get_chars = dom0_read_console,
 192        .put_chars = dom0_write_console,
 193        .notifier_add = notifier_add_irq,
 194        .notifier_del = notifier_del_irq,
 195        .notifier_hangup = notifier_hangup_irq,
 196};
 197
 198static int xen_hvm_console_init(void)
 199{
 200        int r;
 201        uint64_t v = 0;
 202        unsigned long gfn;
 203        struct xencons_info *info;
 204
 205        if (!xen_hvm_domain())
 206                return -ENODEV;
 207
 208        info = vtermno_to_xencons(HVC_COOKIE);
 209        if (!info) {
 210                info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 211                if (!info)
 212                        return -ENOMEM;
 213        } else if (info->intf != NULL) {
 214                /* already configured */
 215                return 0;
 216        }
 217        /*
 218         * If the toolstack (or the hypervisor) hasn't set these values, the
 219         * default value is 0. Even though gfn = 0 and evtchn = 0 are
 220         * theoretically correct values, in practice they never are and they
 221         * mean that a legacy toolstack hasn't initialized the pv console correctly.
 222         */
 223        r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
 224        if (r < 0 || v == 0)
 225                goto err;
 226        info->evtchn = v;
 227        v = 0;
 228        r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
 229        if (r < 0 || v == 0)
 230                goto err;
 231        gfn = v;
 232        info->intf = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE);
 233        if (info->intf == NULL)
 234                goto err;
 235        info->vtermno = HVC_COOKIE;
 236
 237        spin_lock(&xencons_lock);
 238        list_add_tail(&info->list, &xenconsoles);
 239        spin_unlock(&xencons_lock);
 240
 241        return 0;
 242err:
 243        kfree(info);
 244        return -ENODEV;
 245}
 246
 247static int xencons_info_pv_init(struct xencons_info *info, int vtermno)
 248{
 249        info->evtchn = xen_start_info->console.domU.evtchn;
 250        /* GFN == MFN for PV guest */
 251        info->intf = gfn_to_virt(xen_start_info->console.domU.mfn);
 252        info->vtermno = vtermno;
 253
 254        list_add_tail(&info->list, &xenconsoles);
 255
 256        return 0;
 257}
 258
 259static int xen_pv_console_init(void)
 260{
 261        struct xencons_info *info;
 262
 263        if (!xen_pv_domain())
 264                return -ENODEV;
 265
 266        if (!xen_start_info->console.domU.evtchn)
 267                return -ENODEV;
 268
 269        info = vtermno_to_xencons(HVC_COOKIE);
 270        if (!info) {
 271                info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 272                if (!info)
 273                        return -ENOMEM;
 274        } else if (info->intf != NULL) {
 275                /* already configured */
 276                return 0;
 277        }
 278        spin_lock(&xencons_lock);
 279        xencons_info_pv_init(info, HVC_COOKIE);
 280        spin_unlock(&xencons_lock);
 281
 282        return 0;
 283}
 284
 285static int xen_initial_domain_console_init(void)
 286{
 287        struct xencons_info *info;
 288
 289        if (!xen_initial_domain())
 290                return -ENODEV;
 291
 292        info = vtermno_to_xencons(HVC_COOKIE);
 293        if (!info) {
 294                info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 295                if (!info)
 296                        return -ENOMEM;
 297        }
 298
 299        info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
 300        info->vtermno = HVC_COOKIE;
 301
 302        spin_lock(&xencons_lock);
 303        list_add_tail(&info->list, &xenconsoles);
 304        spin_unlock(&xencons_lock);
 305
 306        return 0;
 307}
 308
 309static void xen_console_update_evtchn(struct xencons_info *info)
 310{
 311        if (xen_hvm_domain()) {
 312                uint64_t v = 0;
 313                int err;
 314
 315                err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
 316                if (!err && v)
 317                        info->evtchn = v;
 318        } else
 319                info->evtchn = xen_start_info->console.domU.evtchn;
 320}
 321
 322void xen_console_resume(void)
 323{
 324        struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
 325        if (info != NULL && info->irq) {
 326                if (!xen_initial_domain())
 327                        xen_console_update_evtchn(info);
 328                rebind_evtchn_irq(info->evtchn, info->irq);
 329        }
 330}
 331
 332#ifdef CONFIG_HVC_XEN_FRONTEND
 333static void xencons_disconnect_backend(struct xencons_info *info)
 334{
 335        if (info->irq > 0)
 336                unbind_from_irqhandler(info->irq, NULL);
 337        info->irq = 0;
 338        if (info->evtchn > 0)
 339                xenbus_free_evtchn(info->xbdev, info->evtchn);
 340        info->evtchn = 0;
 341        if (info->gntref > 0)
 342                gnttab_free_grant_references(info->gntref);
 343        info->gntref = 0;
 344        if (info->hvc != NULL)
 345                hvc_remove(info->hvc);
 346        info->hvc = NULL;
 347}
 348
 349static void xencons_free(struct xencons_info *info)
 350{
 351        free_page((unsigned long)info->intf);
 352        info->intf = NULL;
 353        info->vtermno = 0;
 354        kfree(info);
 355}
 356
 357static int xen_console_remove(struct xencons_info *info)
 358{
 359        xencons_disconnect_backend(info);
 360        spin_lock(&xencons_lock);
 361        list_del(&info->list);
 362        spin_unlock(&xencons_lock);
 363        if (info->xbdev != NULL)
 364                xencons_free(info);
 365        else {
 366                if (xen_hvm_domain())
 367                        iounmap(info->intf);
 368                kfree(info);
 369        }
 370        return 0;
 371}
 372
 373static int xencons_remove(struct xenbus_device *dev)
 374{
 375        return xen_console_remove(dev_get_drvdata(&dev->dev));
 376}
 377
 378static int xencons_connect_backend(struct xenbus_device *dev,
 379                                  struct xencons_info *info)
 380{
 381        int ret, evtchn, devid, ref, irq;
 382        struct xenbus_transaction xbt;
 383        grant_ref_t gref_head;
 384
 385        ret = xenbus_alloc_evtchn(dev, &evtchn);
 386        if (ret)
 387                return ret;
 388        info->evtchn = evtchn;
 389        irq = bind_evtchn_to_irq(evtchn);
 390        if (irq < 0)
 391                return irq;
 392        info->irq = irq;
 393        devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
 394        info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
 395                        irq, &domU_hvc_ops, 256);
 396        if (IS_ERR(info->hvc))
 397                return PTR_ERR(info->hvc);
 398        ret = gnttab_alloc_grant_references(1, &gref_head);
 399        if (ret < 0)
 400                return ret;
 401        info->gntref = gref_head;
 402        ref = gnttab_claim_grant_reference(&gref_head);
 403        if (ref < 0)
 404                return ref;
 405        gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
 406                                        virt_to_gfn(info->intf), 0);
 407
 408 again:
 409        ret = xenbus_transaction_start(&xbt);
 410        if (ret) {
 411                xenbus_dev_fatal(dev, ret, "starting transaction");
 412                return ret;
 413        }
 414        ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
 415        if (ret)
 416                goto error_xenbus;
 417        ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
 418                            evtchn);
 419        if (ret)
 420                goto error_xenbus;
 421        ret = xenbus_transaction_end(xbt, 0);
 422        if (ret) {
 423                if (ret == -EAGAIN)
 424                        goto again;
 425                xenbus_dev_fatal(dev, ret, "completing transaction");
 426                return ret;
 427        }
 428
 429        xenbus_switch_state(dev, XenbusStateInitialised);
 430        return 0;
 431
 432 error_xenbus:
 433        xenbus_transaction_end(xbt, 1);
 434        xenbus_dev_fatal(dev, ret, "writing xenstore");
 435        return ret;
 436}
 437
 438static int xencons_probe(struct xenbus_device *dev,
 439                                  const struct xenbus_device_id *id)
 440{
 441        int ret, devid;
 442        struct xencons_info *info;
 443
 444        devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
 445        if (devid == 0)
 446                return -ENODEV;
 447
 448        info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 449        if (!info)
 450                return -ENOMEM;
 451        dev_set_drvdata(&dev->dev, info);
 452        info->xbdev = dev;
 453        info->vtermno = xenbus_devid_to_vtermno(devid);
 454        info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 455        if (!info->intf)
 456                goto error_nomem;
 457
 458        ret = xencons_connect_backend(dev, info);
 459        if (ret < 0)
 460                goto error;
 461        spin_lock(&xencons_lock);
 462        list_add_tail(&info->list, &xenconsoles);
 463        spin_unlock(&xencons_lock);
 464
 465        return 0;
 466
 467 error_nomem:
 468        ret = -ENOMEM;
 469        xenbus_dev_fatal(dev, ret, "allocating device memory");
 470 error:
 471        xencons_disconnect_backend(info);
 472        xencons_free(info);
 473        return ret;
 474}
 475
 476static int xencons_resume(struct xenbus_device *dev)
 477{
 478        struct xencons_info *info = dev_get_drvdata(&dev->dev);
 479
 480        xencons_disconnect_backend(info);
 481        memset(info->intf, 0, XEN_PAGE_SIZE);
 482        return xencons_connect_backend(dev, info);
 483}
 484
 485static void xencons_backend_changed(struct xenbus_device *dev,
 486                                   enum xenbus_state backend_state)
 487{
 488        switch (backend_state) {
 489        case XenbusStateReconfiguring:
 490        case XenbusStateReconfigured:
 491        case XenbusStateInitialising:
 492        case XenbusStateInitialised:
 493        case XenbusStateUnknown:
 494                break;
 495
 496        case XenbusStateInitWait:
 497                break;
 498
 499        case XenbusStateConnected:
 500                xenbus_switch_state(dev, XenbusStateConnected);
 501                break;
 502
 503        case XenbusStateClosed:
 504                if (dev->state == XenbusStateClosed)
 505                        break;
 506                fallthrough;    /* Missed the backend's CLOSING state */
 507        case XenbusStateClosing:
 508                xenbus_frontend_closed(dev);
 509                break;
 510        }
 511}
 512
 513static const struct xenbus_device_id xencons_ids[] = {
 514        { "console" },
 515        { "" }
 516};
 517
 518static struct xenbus_driver xencons_driver = {
 519        .name = "xenconsole",
 520        .ids = xencons_ids,
 521        .probe = xencons_probe,
 522        .remove = xencons_remove,
 523        .resume = xencons_resume,
 524        .otherend_changed = xencons_backend_changed,
 525};
 526#endif /* CONFIG_HVC_XEN_FRONTEND */
 527
 528static int __init xen_hvc_init(void)
 529{
 530        int r;
 531        struct xencons_info *info;
 532        const struct hv_ops *ops;
 533
 534        if (!xen_domain())
 535                return -ENODEV;
 536
 537        if (xen_initial_domain()) {
 538                ops = &dom0_hvc_ops;
 539                r = xen_initial_domain_console_init();
 540                if (r < 0)
 541                        return r;
 542                info = vtermno_to_xencons(HVC_COOKIE);
 543        } else {
 544                ops = &domU_hvc_ops;
 545                if (xen_hvm_domain())
 546                        r = xen_hvm_console_init();
 547                else
 548                        r = xen_pv_console_init();
 549                if (r < 0)
 550                        return r;
 551
 552                info = vtermno_to_xencons(HVC_COOKIE);
 553                info->irq = bind_evtchn_to_irq(info->evtchn);
 554        }
 555        if (info->irq < 0)
 556                info->irq = 0; /* NO_IRQ */
 557        else
 558                irq_set_noprobe(info->irq);
 559
 560        info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
 561        if (IS_ERR(info->hvc)) {
 562                r = PTR_ERR(info->hvc);
 563                spin_lock(&xencons_lock);
 564                list_del(&info->list);
 565                spin_unlock(&xencons_lock);
 566                if (info->irq)
 567                        unbind_from_irqhandler(info->irq, NULL);
 568                kfree(info);
 569                return r;
 570        }
 571
 572        r = 0;
 573#ifdef CONFIG_HVC_XEN_FRONTEND
 574        r = xenbus_register_frontend(&xencons_driver);
 575#endif
 576        return r;
 577}
 578device_initcall(xen_hvc_init);
 579
 580static int xen_cons_init(void)
 581{
 582        const struct hv_ops *ops;
 583
 584        if (!xen_domain())
 585                return 0;
 586
 587        if (xen_initial_domain())
 588                ops = &dom0_hvc_ops;
 589        else {
 590                int r;
 591                ops = &domU_hvc_ops;
 592
 593                if (xen_hvm_domain())
 594                        r = xen_hvm_console_init();
 595                else
 596                        r = xen_pv_console_init();
 597                if (r < 0)
 598                        return r;
 599        }
 600
 601        hvc_instantiate(HVC_COOKIE, 0, ops);
 602        return 0;
 603}
 604console_initcall(xen_cons_init);
 605
 606#ifdef CONFIG_X86
 607static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len)
 608{
 609        if (xen_cpuid_base())
 610                outsb(0xe9, str, len);
 611}
 612#else
 613static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
 614#endif
 615
 616#ifdef CONFIG_EARLY_PRINTK
 617static int __init xenboot_console_setup(struct console *console, char *string)
 618{
 619        static struct xencons_info xenboot;
 620
 621        if (xen_initial_domain() || !xen_pv_domain())
 622                return 0;
 623
 624        return xencons_info_pv_init(&xenboot, 0);
 625}
 626
 627static void xenboot_write_console(struct console *console, const char *string,
 628                                  unsigned len)
 629{
 630        unsigned int linelen, off = 0;
 631        const char *pos;
 632
 633        if (dom0_write_console(0, string, len) >= 0)
 634                return;
 635
 636        if (!xen_pv_domain()) {
 637                xen_hvm_early_write(0, string, len);
 638                return;
 639        }
 640
 641        if (domU_write_console(0, "(early) ", 8) < 0)
 642                return;
 643        while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
 644                linelen = pos-string+off;
 645                if (off + linelen > len)
 646                        break;
 647                domU_write_console(0, string+off, linelen);
 648                domU_write_console(0, "\r\n", 2);
 649                off += linelen + 1;
 650        }
 651        if (off < len)
 652                domU_write_console(0, string+off, len-off);
 653}
 654
 655struct console xenboot_console = {
 656        .name           = "xenboot",
 657        .write          = xenboot_write_console,
 658        .setup          = xenboot_console_setup,
 659        .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
 660        .index          = -1,
 661};
 662#endif  /* CONFIG_EARLY_PRINTK */
 663
 664void xen_raw_console_write(const char *str)
 665{
 666        ssize_t len = strlen(str);
 667        int rc = 0;
 668
 669        if (xen_domain()) {
 670                rc = dom0_write_console(0, str, len);
 671                if (rc != -ENOSYS || !xen_hvm_domain())
 672                        return;
 673        }
 674        xen_hvm_early_write(0, str, len);
 675}
 676
 677void xen_raw_printk(const char *fmt, ...)
 678{
 679        static char buf[512];
 680        va_list ap;
 681
 682        va_start(ap, fmt);
 683        vsnprintf(buf, sizeof(buf), fmt, ap);
 684        va_end(ap);
 685
 686        xen_raw_console_write(buf);
 687}
 688
 689static void xenboot_earlycon_write(struct console *console,
 690                                  const char *string,
 691                                  unsigned len)
 692{
 693        dom0_write_console(0, string, len);
 694}
 695
 696static int __init xenboot_earlycon_setup(struct earlycon_device *device,
 697                                            const char *opt)
 698{
 699        device->con->write = xenboot_earlycon_write;
 700        return 0;
 701}
 702EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);
 703