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