773 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * xen console driver interface to hvc_console.c4 *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 XENCONS_RING_IDX out_cons;41 unsigned int out_cons_same;42 struct hvc_struct *hvc;43 int irq;44 int vtermno;45 grant_ref_t gntref;46 spinlock_t ring_lock;47};48 49static LIST_HEAD(xenconsoles);50static DEFINE_SPINLOCK(xencons_lock);51 52/* ------------------------------------------------------------------ */53 54static struct xencons_info *vtermno_to_xencons(int vtermno)55{56 struct xencons_info *entry, *ret = NULL;57 unsigned long flags;58 59 spin_lock_irqsave(&xencons_lock, flags);60 if (list_empty(&xenconsoles)) {61 spin_unlock_irqrestore(&xencons_lock, flags);62 return NULL;63 }64 65 list_for_each_entry(entry, &xenconsoles, list) {66 if (entry->vtermno == vtermno) {67 ret = entry;68 break;69 }70 }71 spin_unlock_irqrestore(&xencons_lock, flags);72 73 return ret;74}75 76static inline int xenbus_devid_to_vtermno(int devid)77{78 return devid + HVC_COOKIE;79}80 81static inline void notify_daemon(struct xencons_info *cons)82{83 /* Use evtchn: this is called early, before irq is set up. */84 notify_remote_via_evtchn(cons->evtchn);85}86 87static ssize_t __write_console(struct xencons_info *xencons,88 const u8 *data, size_t len)89{90 XENCONS_RING_IDX cons, prod;91 struct xencons_interface *intf = xencons->intf;92 unsigned long flags;93 size_t sent = 0;94 95 spin_lock_irqsave(&xencons->ring_lock, flags);96 cons = intf->out_cons;97 prod = intf->out_prod;98 mb(); /* update queue values before going on */99 100 if ((prod - cons) > sizeof(intf->out)) {101 spin_unlock_irqrestore(&xencons->ring_lock, flags);102 pr_err_once("xencons: Illegal ring page indices");103 return -EINVAL;104 }105 106 while ((sent < len) && ((prod - cons) < sizeof(intf->out)))107 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];108 109 wmb(); /* write ring before updating pointer */110 intf->out_prod = prod;111 spin_unlock_irqrestore(&xencons->ring_lock, flags);112 113 if (sent)114 notify_daemon(xencons);115 return sent;116}117 118static ssize_t domU_write_console(uint32_t vtermno, const u8 *data, size_t len)119{120 struct xencons_info *cons = vtermno_to_xencons(vtermno);121 size_t ret = len;122 123 if (cons == NULL)124 return -EINVAL;125 126 /*127 * Make sure the whole buffer is emitted, polling if128 * necessary. We don't ever want to rely on the hvc daemon129 * because the most interesting console output is when the130 * kernel is crippled.131 */132 while (len) {133 ssize_t sent = __write_console(cons, data, len);134 135 if (sent < 0)136 return sent;137 138 data += sent;139 len -= sent;140 141 if (unlikely(len))142 HYPERVISOR_sched_op(SCHEDOP_yield, NULL);143 }144 145 return ret;146}147 148static ssize_t domU_read_console(uint32_t vtermno, u8 *buf, size_t len)149{150 struct xencons_interface *intf;151 XENCONS_RING_IDX cons, prod;152 struct xencons_info *xencons = vtermno_to_xencons(vtermno);153 unsigned int eoiflag = 0;154 unsigned long flags;155 size_t recv = 0;156 157 if (xencons == NULL)158 return -EINVAL;159 intf = xencons->intf;160 161 spin_lock_irqsave(&xencons->ring_lock, flags);162 cons = intf->in_cons;163 prod = intf->in_prod;164 mb(); /* get pointers before reading ring */165 166 if ((prod - cons) > sizeof(intf->in)) {167 spin_unlock_irqrestore(&xencons->ring_lock, flags);168 pr_err_once("xencons: Illegal ring page indices");169 return -EINVAL;170 }171 172 while (cons != prod && recv < len)173 buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];174 175 mb(); /* read ring before consuming */176 intf->in_cons = cons;177 178 /*179 * When to mark interrupt having been spurious:180 * - there was no new data to be read, and181 * - the backend did not consume some output bytes, and182 * - the previous round with no read data didn't see consumed bytes183 * (we might have a race with an interrupt being in flight while184 * updating xencons->out_cons, so account for that by allowing one185 * round without any visible reason)186 */187 if (intf->out_cons != xencons->out_cons) {188 xencons->out_cons = intf->out_cons;189 xencons->out_cons_same = 0;190 }191 if (!recv && xencons->out_cons_same++ > 1) {192 eoiflag = XEN_EOI_FLAG_SPURIOUS;193 }194 spin_unlock_irqrestore(&xencons->ring_lock, flags);195 196 if (recv) {197 notify_daemon(xencons);198 }199 200 xen_irq_lateeoi(xencons->irq, eoiflag);201 202 return recv;203}204 205static const struct hv_ops domU_hvc_ops = {206 .get_chars = domU_read_console,207 .put_chars = domU_write_console,208 .notifier_add = notifier_add_irq,209 .notifier_del = notifier_del_irq,210 .notifier_hangup = notifier_hangup_irq,211};212 213static ssize_t dom0_read_console(uint32_t vtermno, u8 *buf, size_t len)214{215 return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);216}217 218/*219 * Either for a dom0 to write to the system console, or a domU with a220 * debug version of Xen221 */222static ssize_t dom0_write_console(uint32_t vtermno, const u8 *str, size_t len)223{224 int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (u8 *)str);225 if (rc < 0)226 return rc;227 228 return len;229}230 231static const struct hv_ops dom0_hvc_ops = {232 .get_chars = dom0_read_console,233 .put_chars = dom0_write_console,234 .notifier_add = notifier_add_irq,235 .notifier_del = notifier_del_irq,236 .notifier_hangup = notifier_hangup_irq,237};238 239static int xen_hvm_console_init(void)240{241 int r;242 uint64_t v = 0;243 unsigned long gfn, flags;244 struct xencons_info *info;245 246 if (!xen_hvm_domain())247 return -ENODEV;248 249 info = vtermno_to_xencons(HVC_COOKIE);250 if (!info) {251 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);252 if (!info)253 return -ENOMEM;254 spin_lock_init(&info->ring_lock);255 } else if (info->intf != NULL) {256 /* already configured */257 return 0;258 }259 /*260 * If the toolstack (or the hypervisor) hasn't set these values, the261 * default value is 0. Even though gfn = 0 and evtchn = 0 are262 * theoretically correct values, in practice they never are and they263 * mean that a legacy toolstack hasn't initialized the pv console correctly.264 */265 r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);266 if (r < 0 || v == 0)267 goto err;268 info->evtchn = v;269 v = 0;270 r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);271 if (r < 0 || v == 0)272 goto err;273 gfn = v;274 info->intf = memremap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE, MEMREMAP_WB);275 if (info->intf == NULL)276 goto err;277 info->vtermno = HVC_COOKIE;278 279 spin_lock_irqsave(&xencons_lock, flags);280 list_add_tail(&info->list, &xenconsoles);281 spin_unlock_irqrestore(&xencons_lock, flags);282 283 return 0;284err:285 kfree(info);286 return -ENODEV;287}288 289static int xencons_info_pv_init(struct xencons_info *info, int vtermno)290{291 spin_lock_init(&info->ring_lock);292 info->evtchn = xen_start_info->console.domU.evtchn;293 /* GFN == MFN for PV guest */294 info->intf = gfn_to_virt(xen_start_info->console.domU.mfn);295 info->vtermno = vtermno;296 297 list_add_tail(&info->list, &xenconsoles);298 299 return 0;300}301 302static int xen_pv_console_init(void)303{304 struct xencons_info *info;305 unsigned long flags;306 307 if (!xen_pv_domain())308 return -ENODEV;309 310 if (!xen_start_info->console.domU.evtchn)311 return -ENODEV;312 313 info = vtermno_to_xencons(HVC_COOKIE);314 if (!info) {315 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);316 if (!info)317 return -ENOMEM;318 } else if (info->intf != NULL) {319 /* already configured */320 return 0;321 }322 spin_lock_irqsave(&xencons_lock, flags);323 xencons_info_pv_init(info, HVC_COOKIE);324 spin_unlock_irqrestore(&xencons_lock, flags);325 326 return 0;327}328 329static int xen_initial_domain_console_init(void)330{331 struct xencons_info *info;332 unsigned long flags;333 334 if (!xen_initial_domain())335 return -ENODEV;336 337 info = vtermno_to_xencons(HVC_COOKIE);338 if (!info) {339 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);340 if (!info)341 return -ENOMEM;342 spin_lock_init(&info->ring_lock);343 }344 345 info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);346 info->vtermno = HVC_COOKIE;347 348 spin_lock_irqsave(&xencons_lock, flags);349 list_add_tail(&info->list, &xenconsoles);350 spin_unlock_irqrestore(&xencons_lock, flags);351 352 return 0;353}354 355static void xen_console_update_evtchn(struct xencons_info *info)356{357 if (xen_hvm_domain()) {358 uint64_t v = 0;359 int err;360 361 err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);362 if (!err && v)363 info->evtchn = v;364 } else365 info->evtchn = xen_start_info->console.domU.evtchn;366}367 368void xen_console_resume(void)369{370 struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);371 if (info != NULL && info->irq) {372 if (!xen_initial_domain())373 xen_console_update_evtchn(info);374 rebind_evtchn_irq(info->evtchn, info->irq);375 }376}377 378#ifdef CONFIG_HVC_XEN_FRONTEND379static void xencons_disconnect_backend(struct xencons_info *info)380{381 if (info->hvc != NULL)382 hvc_remove(info->hvc);383 info->hvc = NULL;384 if (info->irq > 0) {385 evtchn_put(info->evtchn);386 info->irq = 0;387 info->evtchn = 0;388 }389 /* evtchn_put() will also close it so this is only an error path */390 if (info->evtchn > 0)391 xenbus_free_evtchn(info->xbdev, info->evtchn);392 info->evtchn = 0;393 if (info->gntref > 0)394 gnttab_free_grant_references(info->gntref);395 info->gntref = 0;396}397 398static void xencons_free(struct xencons_info *info)399{400 free_page((unsigned long)info->intf);401 info->intf = NULL;402 info->vtermno = 0;403 kfree(info);404}405 406static int xen_console_remove(struct xencons_info *info)407{408 unsigned long flags;409 410 xencons_disconnect_backend(info);411 spin_lock_irqsave(&xencons_lock, flags);412 list_del(&info->list);413 spin_unlock_irqrestore(&xencons_lock, flags);414 if (info->xbdev != NULL)415 xencons_free(info);416 else {417 if (xen_hvm_domain())418 iounmap(info->intf);419 kfree(info);420 }421 return 0;422}423 424static void xencons_remove(struct xenbus_device *dev)425{426 xen_console_remove(dev_get_drvdata(&dev->dev));427}428 429static int xencons_connect_backend(struct xenbus_device *dev,430 struct xencons_info *info)431{432 int ret, evtchn, devid, ref, irq;433 struct xenbus_transaction xbt;434 grant_ref_t gref_head;435 436 ret = xenbus_alloc_evtchn(dev, &evtchn);437 if (ret)438 return ret;439 info->evtchn = evtchn;440 irq = bind_evtchn_to_irq_lateeoi(evtchn);441 if (irq < 0)442 return irq;443 info->irq = irq;444 devid = dev->nodename[strlen(dev->nodename) - 1] - '0';445 info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),446 irq, &domU_hvc_ops, 256);447 if (IS_ERR(info->hvc))448 return PTR_ERR(info->hvc);449 ret = gnttab_alloc_grant_references(1, &gref_head);450 if (ret < 0)451 return ret;452 info->gntref = gref_head;453 ref = gnttab_claim_grant_reference(&gref_head);454 if (ref < 0)455 return ref;456 gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,457 virt_to_gfn(info->intf), 0);458 459 again:460 ret = xenbus_transaction_start(&xbt);461 if (ret) {462 xenbus_dev_fatal(dev, ret, "starting transaction");463 return ret;464 }465 ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);466 if (ret)467 goto error_xenbus;468 ret = xenbus_printf(xbt, dev->nodename, "port", "%u",469 evtchn);470 if (ret)471 goto error_xenbus;472 ret = xenbus_transaction_end(xbt, 0);473 if (ret) {474 if (ret == -EAGAIN)475 goto again;476 xenbus_dev_fatal(dev, ret, "completing transaction");477 return ret;478 }479 480 xenbus_switch_state(dev, XenbusStateInitialised);481 return 0;482 483 error_xenbus:484 xenbus_transaction_end(xbt, 1);485 xenbus_dev_fatal(dev, ret, "writing xenstore");486 return ret;487}488 489static int xencons_probe(struct xenbus_device *dev,490 const struct xenbus_device_id *id)491{492 int ret, devid;493 struct xencons_info *info;494 unsigned long flags;495 496 devid = dev->nodename[strlen(dev->nodename) - 1] - '0';497 if (devid == 0)498 return -ENODEV;499 500 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);501 if (!info)502 return -ENOMEM;503 spin_lock_init(&info->ring_lock);504 dev_set_drvdata(&dev->dev, info);505 info->xbdev = dev;506 info->vtermno = xenbus_devid_to_vtermno(devid);507 info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);508 if (!info->intf)509 goto error_nomem;510 511 ret = xencons_connect_backend(dev, info);512 if (ret < 0)513 goto error;514 spin_lock_irqsave(&xencons_lock, flags);515 list_add_tail(&info->list, &xenconsoles);516 spin_unlock_irqrestore(&xencons_lock, flags);517 518 return 0;519 520 error_nomem:521 ret = -ENOMEM;522 xenbus_dev_fatal(dev, ret, "allocating device memory");523 error:524 xencons_disconnect_backend(info);525 xencons_free(info);526 return ret;527}528 529static int xencons_resume(struct xenbus_device *dev)530{531 struct xencons_info *info = dev_get_drvdata(&dev->dev);532 533 xencons_disconnect_backend(info);534 memset(info->intf, 0, XEN_PAGE_SIZE);535 return xencons_connect_backend(dev, info);536}537 538static void xencons_backend_changed(struct xenbus_device *dev,539 enum xenbus_state backend_state)540{541 switch (backend_state) {542 case XenbusStateReconfiguring:543 case XenbusStateReconfigured:544 case XenbusStateInitialising:545 case XenbusStateInitialised:546 case XenbusStateUnknown:547 break;548 549 case XenbusStateInitWait:550 break;551 552 case XenbusStateConnected:553 xenbus_switch_state(dev, XenbusStateConnected);554 break;555 556 case XenbusStateClosed:557 if (dev->state == XenbusStateClosed)558 break;559 fallthrough; /* Missed the backend's CLOSING state */560 case XenbusStateClosing: {561 struct xencons_info *info = dev_get_drvdata(&dev->dev);562 563 /*564 * Don't tear down the evtchn and grant ref before the other565 * end has disconnected, but do stop userspace from trying566 * to use the device before we allow the backend to close.567 */568 if (info->hvc) {569 hvc_remove(info->hvc);570 info->hvc = NULL;571 }572 573 xenbus_frontend_closed(dev);574 break;575 }576 }577}578 579static const struct xenbus_device_id xencons_ids[] = {580 { "console" },581 { "" }582};583 584static struct xenbus_driver xencons_driver = {585 .name = "xenconsole",586 .ids = xencons_ids,587 .probe = xencons_probe,588 .remove = xencons_remove,589 .resume = xencons_resume,590 .otherend_changed = xencons_backend_changed,591 .not_essential = true,592};593#endif /* CONFIG_HVC_XEN_FRONTEND */594 595static int __init xen_hvc_init(void)596{597 int r;598 struct xencons_info *info;599 const struct hv_ops *ops;600 601 if (!xen_domain())602 return -ENODEV;603 604 if (xen_initial_domain()) {605 ops = &dom0_hvc_ops;606 r = xen_initial_domain_console_init();607 if (r < 0)608 goto register_fe;609 info = vtermno_to_xencons(HVC_COOKIE);610 } else {611 ops = &domU_hvc_ops;612 if (xen_hvm_domain())613 r = xen_hvm_console_init();614 else615 r = xen_pv_console_init();616 if (r < 0)617 goto register_fe;618 619 info = vtermno_to_xencons(HVC_COOKIE);620 info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);621 }622 if (info->irq < 0)623 info->irq = 0; /* NO_IRQ */624 else625 irq_set_noprobe(info->irq);626 627 info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);628 if (IS_ERR(info->hvc)) {629 unsigned long flags;630 631 r = PTR_ERR(info->hvc);632 spin_lock_irqsave(&xencons_lock, flags);633 list_del(&info->list);634 spin_unlock_irqrestore(&xencons_lock, flags);635 if (info->irq)636 evtchn_put(info->evtchn);637 kfree(info);638 return r;639 }640 641 r = 0;642 register_fe:643#ifdef CONFIG_HVC_XEN_FRONTEND644 r = xenbus_register_frontend(&xencons_driver);645#endif646 return r;647}648device_initcall(xen_hvc_init);649 650static int xen_cons_init(void)651{652 const struct hv_ops *ops;653 654 if (!xen_domain())655 return 0;656 657 if (xen_initial_domain())658 ops = &dom0_hvc_ops;659 else {660 int r;661 ops = &domU_hvc_ops;662 663 if (xen_hvm_domain())664 r = xen_hvm_console_init();665 else666 r = xen_pv_console_init();667 if (r < 0)668 return r;669 }670 671 hvc_instantiate(HVC_COOKIE, 0, ops);672 return 0;673}674console_initcall(xen_cons_init);675 676#ifdef CONFIG_X86677static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len)678{679 if (xen_cpuid_base())680 outsb(0xe9, str, len);681}682#else683static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }684#endif685 686#ifdef CONFIG_EARLY_PRINTK687static int __init xenboot_console_setup(struct console *console, char *string)688{689 static struct xencons_info xenboot;690 691 if (xen_initial_domain() || !xen_pv_domain())692 return 0;693 694 return xencons_info_pv_init(&xenboot, 0);695}696 697static void xenboot_write_console(struct console *console, const char *string,698 unsigned len)699{700 unsigned int linelen, off = 0;701 const char *pos;702 703 if (dom0_write_console(0, string, len) >= 0)704 return;705 706 if (!xen_pv_domain()) {707 xen_hvm_early_write(0, string, len);708 return;709 }710 711 if (domU_write_console(0, "(early) ", 8) < 0)712 return;713 while (off < len && NULL != (pos = strchr(string+off, '\n'))) {714 linelen = pos-string+off;715 if (off + linelen > len)716 break;717 domU_write_console(0, string+off, linelen);718 domU_write_console(0, "\r\n", 2);719 off += linelen + 1;720 }721 if (off < len)722 domU_write_console(0, string+off, len-off);723}724 725struct console xenboot_console = {726 .name = "xenboot",727 .write = xenboot_write_console,728 .setup = xenboot_console_setup,729 .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,730 .index = -1,731};732#endif /* CONFIG_EARLY_PRINTK */733 734void xen_raw_console_write(const char *str)735{736 ssize_t len = strlen(str);737 int rc = 0;738 739 if (xen_domain()) {740 rc = dom0_write_console(0, str, len);741 if (rc != -ENOSYS || !xen_hvm_domain())742 return;743 }744 xen_hvm_early_write(0, str, len);745}746 747void xen_raw_printk(const char *fmt, ...)748{749 static char buf[512];750 va_list ap;751 752 va_start(ap, fmt);753 vsnprintf(buf, sizeof(buf), fmt, ap);754 va_end(ap);755 756 xen_raw_console_write(buf);757}758 759static void xenboot_earlycon_write(struct console *console,760 const char *string,761 unsigned len)762{763 dom0_write_console(0, string, len);764}765 766static int __init xenboot_earlycon_setup(struct earlycon_device *device,767 const char *opt)768{769 device->con->write = xenboot_earlycon_write;770 return 0;771}772EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);773