1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2012 Gary Mills 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/archsystm.h> 31 #include <sys/boot_console.h> 32 #include <sys/panic.h> 33 #include <sys/ctype.h> 34 #if defined(__xpv) 35 #include <sys/hypervisor.h> 36 #endif /* __xpv */ 37 38 #include "boot_serial.h" 39 #include "boot_vga.h" 40 41 #if defined(_BOOT) 42 #include <dboot/dboot_asm.h> 43 #include <dboot/dboot_xboot.h> 44 #else /* _BOOT */ 45 #include <sys/bootconf.h> 46 #if defined(__xpv) 47 #include <sys/evtchn_impl.h> 48 #endif /* __xpv */ 49 static char *defcons_buf; 50 static char *defcons_cur; 51 #endif /* _BOOT */ 52 53 #if defined(__xpv) 54 extern void bcons_init_xen(char *); 55 extern void bcons_putchar_xen(int); 56 extern int bcons_getchar_xen(void); 57 extern int bcons_ischar_xen(void); 58 #endif /* __xpv */ 59 60 static int cons_color = CONS_COLOR; 61 static int console = CONS_SCREEN_TEXT; 62 static int tty_num = 0; 63 static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; 64 static char *boot_line; 65 static struct boot_env { 66 char *be_env; /* ends with double ascii nul */ 67 size_t be_size; /* size of the environment, including nul */ 68 } boot_env; 69 70 static int serial_ischar(void); 71 static int serial_getchar(void); 72 static void serial_putchar(int); 73 static void serial_adjust_prop(void); 74 75 #if !defined(_BOOT) 76 /* Set if the console or mode are expressed in the boot line */ 77 static int console_set, console_mode_set; 78 #endif 79 80 #if defined(__xpv) 81 static int console_hypervisor_redirect = B_FALSE; 82 static int console_hypervisor_device = CONS_INVALID; 83 static int console_hypervisor_tty_num = 0; 84 85 /* Obtain the hypervisor console type */ 86 int 87 console_hypervisor_dev_type(int *tnum) 88 { 89 if (tnum != NULL) 90 *tnum = console_hypervisor_tty_num; 91 return (console_hypervisor_device); 92 } 93 #endif /* __xpv */ 94 95 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */ 96 void 97 clear_screen(void) 98 { 99 /* 100 * XXX should set vga mode so we don't depend on the 101 * state left by the boot loader. Note that we have to 102 * enable the cursor before clearing the screen since 103 * the cursor position is dependant upon the cursor 104 * skew, which is initialized by vga_cursor_display() 105 */ 106 vga_cursor_display(); 107 vga_clear(cons_color); 108 vga_setpos(0, 0); 109 } 110 111 /* Put the character C on the screen. */ 112 static void 113 screen_putchar(int c) 114 { 115 int row, col; 116 117 vga_getpos(&row, &col); 118 switch (c) { 119 case '\t': 120 col += 8 - (col % 8); 121 if (col == VGA_TEXT_COLS) 122 col = 79; 123 vga_setpos(row, col); 124 break; 125 126 case '\r': 127 vga_setpos(row, 0); 128 break; 129 130 case '\b': 131 if (col > 0) 132 vga_setpos(row, col - 1); 133 break; 134 135 case '\n': 136 if (row < VGA_TEXT_ROWS - 1) 137 vga_setpos(row + 1, col); 138 else 139 vga_scroll(cons_color); 140 break; 141 142 default: 143 vga_drawc(c, cons_color); 144 if (col < VGA_TEXT_COLS -1) 145 vga_setpos(row, col + 1); 146 else if (row < VGA_TEXT_ROWS - 1) 147 vga_setpos(row + 1, 0); 148 else { 149 vga_setpos(row, 0); 150 vga_scroll(cons_color); 151 } 152 break; 153 } 154 } 155 156 static int port; 157 158 static void 159 serial_init(void) 160 { 161 port = tty_addr[tty_num]; 162 163 outb(port + ISR, 0x20); 164 if (inb(port + ISR) & 0x20) { 165 /* 166 * 82510 chip is present 167 */ 168 outb(port + DAT+7, 0x04); /* clear status */ 169 outb(port + ISR, 0x40); /* set to bank 2 */ 170 outb(port + MCR, 0x08); /* IMD */ 171 outb(port + DAT, 0x21); /* FMD */ 172 outb(port + ISR, 0x00); /* set to bank 0 */ 173 } else { 174 /* 175 * set the UART in FIFO mode if it has FIFO buffers. 176 * use 16550 fifo reset sequence specified in NS 177 * application note. disable fifos until chip is 178 * initialized. 179 */ 180 outb(port + FIFOR, 0x00); /* clear */ 181 outb(port + FIFOR, FIFO_ON); /* enable */ 182 outb(port + FIFOR, FIFO_ON|FIFORXFLSH); /* reset */ 183 outb(port + FIFOR, 184 FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80); 185 if ((inb(port + ISR) & 0xc0) != 0xc0) { 186 /* 187 * no fifo buffers so disable fifos. 188 * this is true for 8250's 189 */ 190 outb(port + FIFOR, 0x00); 191 } 192 } 193 194 /* disable interrupts */ 195 outb(port + ICR, 0); 196 197 #if !defined(_BOOT) 198 if (IN_XPV_PANIC()) 199 return; 200 #endif 201 202 /* adjust setting based on tty properties */ 203 serial_adjust_prop(); 204 205 #if defined(_BOOT) 206 /* 207 * Do a full reset to match console behavior. 208 * 0x1B + c - reset everything 209 */ 210 serial_putchar(0x1B); 211 serial_putchar('c'); 212 #endif 213 } 214 215 /* Advance str pointer past white space */ 216 #define EAT_WHITE_SPACE(str) { \ 217 while ((*str != '\0') && ISSPACE(*str)) \ 218 str++; \ 219 } 220 221 /* 222 * boot_line is set when we call here. Search it for the argument name, 223 * and if found, return a pointer to it. 224 */ 225 static char * 226 find_boot_line_prop(const char *name) 227 { 228 char *ptr; 229 char *ret = NULL; 230 char end_char; 231 size_t len; 232 233 if (boot_line == NULL) 234 return (NULL); 235 236 len = strlen(name); 237 238 /* 239 * We have two nested loops here: the outer loop discards all options 240 * except -B, and the inner loop parses the -B options looking for 241 * the one we're interested in. 242 */ 243 for (ptr = boot_line; *ptr != '\0'; ptr++) { 244 EAT_WHITE_SPACE(ptr); 245 246 if (*ptr == '-') { 247 ptr++; 248 while ((*ptr != '\0') && (*ptr != 'B') && 249 !ISSPACE(*ptr)) 250 ptr++; 251 if (*ptr == '\0') 252 goto out; 253 else if (*ptr != 'B') 254 continue; 255 } else { 256 while ((*ptr != '\0') && !ISSPACE(*ptr)) 257 ptr++; 258 if (*ptr == '\0') 259 goto out; 260 continue; 261 } 262 263 do { 264 ptr++; 265 EAT_WHITE_SPACE(ptr); 266 267 if ((strncmp(ptr, name, len) == 0) && 268 (ptr[len] == '=')) { 269 ptr += len + 1; 270 if ((*ptr == '\'') || (*ptr == '"')) { 271 ret = ptr + 1; 272 end_char = *ptr; 273 ptr++; 274 } else { 275 ret = ptr; 276 end_char = ','; 277 } 278 goto consume_property; 279 } 280 281 /* 282 * We have a property, and it's not the one we're 283 * interested in. Skip the property name. A name 284 * can end with '=', a comma, or white space. 285 */ 286 while ((*ptr != '\0') && (*ptr != '=') && 287 (*ptr != ',') && (!ISSPACE(*ptr))) 288 ptr++; 289 290 /* 291 * We only want to go through the rest of the inner 292 * loop if we have a comma. If we have a property 293 * name without a value, either continue or break. 294 */ 295 if (*ptr == '\0') 296 goto out; 297 else if (*ptr == ',') 298 continue; 299 else if (ISSPACE(*ptr)) 300 break; 301 ptr++; 302 303 /* 304 * Is the property quoted? 305 */ 306 if ((*ptr == '\'') || (*ptr == '"')) { 307 end_char = *ptr; 308 ptr++; 309 } else { 310 /* 311 * Not quoted, so the string ends at a comma 312 * or at white space. Deal with white space 313 * later. 314 */ 315 end_char = ','; 316 } 317 318 /* 319 * Now, we can ignore any characters until we find 320 * end_char. 321 */ 322 consume_property: 323 for (; (*ptr != '\0') && (*ptr != end_char); ptr++) { 324 if ((end_char == ',') && ISSPACE(*ptr)) 325 break; 326 } 327 if (*ptr && (*ptr != ',') && !ISSPACE(*ptr)) 328 ptr++; 329 } while (*ptr == ','); 330 } 331 out: 332 return (ret); 333 } 334 335 /* 336 * Find prop from boot env module. The data in module is list of C strings 337 * name=value, the list is terminated by double nul. 338 */ 339 static const char * 340 find_boot_env_prop(const char *name) 341 { 342 char *ptr; 343 size_t len; 344 uintptr_t size; 345 346 if (boot_env.be_env == NULL) 347 return (NULL); 348 349 ptr = boot_env.be_env; 350 len = strlen(name); 351 352 /* 353 * Make sure we have at least len + 2 bytes in the environment. 354 * We are looking for name=value\0 constructs, and the environment 355 * itself is terminated by '\0'. 356 */ 357 if (boot_env.be_size < len + 2) 358 return (NULL); 359 360 do { 361 if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) { 362 ptr += len + 1; 363 return (ptr); 364 } 365 /* find the first '\0' */ 366 while (*ptr != '\0') { 367 ptr++; 368 size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env; 369 if (size > boot_env.be_size) 370 return (NULL); 371 } 372 ptr++; 373 374 /* If the remainder is shorter than name + 2, get out. */ 375 size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env; 376 if (boot_env.be_size - size < len + 2) 377 return (NULL); 378 } while (*ptr != '\0'); 379 return (NULL); 380 } 381 382 /* 383 * Get prop value from either command line or boot environment. 384 * We always check kernel command line first, as this will keep the 385 * functionality and will allow user to override the values in environment. 386 */ 387 const char * 388 find_boot_prop(const char *name) 389 { 390 const char *value = find_boot_line_prop(name); 391 392 if (value == NULL) 393 value = find_boot_env_prop(name); 394 return (value); 395 } 396 397 #define MATCHES(p, pat) \ 398 (strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0) 399 400 #define SKIP(p, c) \ 401 while (*(p) != 0 && *p != (c)) \ 402 ++(p); \ 403 if (*(p) == (c)) \ 404 ++(p); 405 406 /* 407 * find a tty mode property either from cmdline or from boot properties 408 */ 409 static const char * 410 get_mode_value(char *name) 411 { 412 /* 413 * when specified on boot line it looks like "name" "=".... 414 */ 415 if (boot_line != NULL) { 416 return (find_boot_prop(name)); 417 } 418 419 #if defined(_BOOT) 420 return (NULL); 421 #else 422 /* 423 * if we're running in the full kernel we check the bootenv.rc settings 424 */ 425 { 426 static char propval[20]; 427 428 propval[0] = 0; 429 if (do_bsys_getproplen(NULL, name) <= 0) 430 return (NULL); 431 (void) do_bsys_getprop(NULL, name, propval); 432 return (propval); 433 } 434 #endif 435 } 436 437 /* 438 * adjust serial port based on properties 439 * These come either from the cmdline or from boot properties. 440 */ 441 static void 442 serial_adjust_prop(void) 443 { 444 char propname[20]; 445 const char *propval; 446 const char *p; 447 ulong_t baud; 448 uchar_t lcr = 0; 449 uchar_t mcr = DTR | RTS; 450 451 (void) strcpy(propname, "ttyX-mode"); 452 propname[3] = 'a' + tty_num; 453 propval = get_mode_value(propname); 454 if (propval == NULL) 455 propval = "9600,8,n,1,-"; 456 #if !defined(_BOOT) 457 else 458 console_mode_set = 1; 459 #endif 460 461 /* property is of the form: "9600,8,n,1,-" */ 462 p = propval; 463 if (MATCHES(p, "110,")) 464 baud = ASY110; 465 else if (MATCHES(p, "150,")) 466 baud = ASY150; 467 else if (MATCHES(p, "300,")) 468 baud = ASY300; 469 else if (MATCHES(p, "600,")) 470 baud = ASY600; 471 else if (MATCHES(p, "1200,")) 472 baud = ASY1200; 473 else if (MATCHES(p, "2400,")) 474 baud = ASY2400; 475 else if (MATCHES(p, "4800,")) 476 baud = ASY4800; 477 else if (MATCHES(p, "19200,")) 478 baud = ASY19200; 479 else if (MATCHES(p, "38400,")) 480 baud = ASY38400; 481 else if (MATCHES(p, "57600,")) 482 baud = ASY57600; 483 else if (MATCHES(p, "115200,")) 484 baud = ASY115200; 485 else { 486 baud = ASY9600; 487 SKIP(p, ','); 488 } 489 outb(port + LCR, DLAB); 490 outb(port + DAT + DLL, baud & 0xff); 491 outb(port + DAT + DLH, (baud >> 8) & 0xff); 492 493 switch (*p) { 494 case '5': 495 lcr |= BITS5; 496 ++p; 497 break; 498 case '6': 499 lcr |= BITS6; 500 ++p; 501 break; 502 case '7': 503 lcr |= BITS7; 504 ++p; 505 break; 506 case '8': 507 ++p; 508 /* FALLTHROUGH */ 509 default: 510 lcr |= BITS8; 511 break; 512 } 513 514 SKIP(p, ','); 515 516 switch (*p) { 517 case 'n': 518 lcr |= PARITY_NONE; 519 ++p; 520 break; 521 case 'o': 522 lcr |= PARITY_ODD; 523 ++p; 524 break; 525 case 'e': 526 ++p; 527 /* FALLTHROUGH */ 528 default: 529 lcr |= PARITY_EVEN; 530 break; 531 } 532 533 534 SKIP(p, ','); 535 536 switch (*p) { 537 case '1': 538 /* STOP1 is 0 */ 539 ++p; 540 break; 541 default: 542 lcr |= STOP2; 543 break; 544 } 545 /* set parity bits */ 546 outb(port + LCR, lcr); 547 548 (void) strcpy(propname, "ttyX-rts-dtr-off"); 549 propname[3] = 'a' + tty_num; 550 propval = get_mode_value(propname); 551 if (propval == NULL) 552 propval = "false"; 553 if (propval[0] != 'f' && propval[0] != 'F') 554 mcr = 0; 555 /* set modem control bits */ 556 outb(port + MCR, mcr | OUT2); 557 } 558 559 /* Obtain the console type */ 560 int 561 boot_console_type(int *tnum) 562 { 563 if (tnum != NULL) 564 *tnum = tty_num; 565 return (console); 566 } 567 568 /* 569 * A structure to map console names to values. 570 */ 571 typedef struct { 572 char *name; 573 int value; 574 } console_value_t; 575 576 console_value_t console_devices[] = { 577 { "ttya", CONS_TTY }, /* 0 */ 578 { "ttyb", CONS_TTY }, /* 1 */ 579 { "ttyc", CONS_TTY }, /* 2 */ 580 { "ttyd", CONS_TTY }, /* 3 */ 581 { "text", CONS_SCREEN_TEXT }, 582 { "graphics", CONS_SCREEN_GRAPHICS }, 583 #if defined(__xpv) 584 { "hypervisor", CONS_HYPERVISOR }, 585 #endif 586 #if !defined(_BOOT) 587 { "usb-serial", CONS_USBSER }, 588 #endif 589 { NULL, CONS_INVALID } 590 }; 591 592 static void 593 bcons_init_env(struct xboot_info *xbi) 594 { 595 uint32_t i; 596 struct boot_modules *modules; 597 598 modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules; 599 for (i = 0; i < xbi->bi_module_cnt; i++) { 600 if (modules[i].bm_type == BMT_ENV) 601 break; 602 } 603 if (i == xbi->bi_module_cnt) 604 return; 605 606 boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr; 607 boot_env.be_size = modules[i].bm_size; 608 } 609 610 void 611 bcons_init(struct xboot_info *xbi) 612 { 613 console_value_t *consolep; 614 size_t len, cons_len; 615 const char *cons_str; 616 #if !defined(_BOOT) 617 static char console_text[] = "text"; 618 extern int post_fastreboot; 619 #endif 620 621 /* Set up data to fetch properties from commad line and boot env. */ 622 boot_line = (char *)(uintptr_t)xbi->bi_cmdline; 623 bcons_init_env(xbi); 624 console = CONS_INVALID; 625 626 #if defined(__xpv) 627 bcons_init_xen(boot_line); 628 #endif /* __xpv */ 629 630 cons_str = find_boot_prop("console"); 631 if (cons_str == NULL) 632 cons_str = find_boot_prop("output-device"); 633 634 #if !defined(_BOOT) 635 if (post_fastreboot && strcmp(cons_str, "graphics") == 0) 636 cons_str = console_text; 637 #endif 638 639 /* 640 * Go through the console_devices array trying to match the string 641 * we were given. The string on the command line must end with 642 * a comma or white space. 643 */ 644 if (cons_str != NULL) { 645 int n; 646 647 cons_len = strlen(cons_str); 648 for (n = 0; console_devices[n].name != NULL; n++) { 649 consolep = &console_devices[n]; 650 len = strlen(consolep->name); 651 if ((len <= cons_len) && ((cons_str[len] == '\0') || 652 (cons_str[len] == ',') || (cons_str[len] == '\'') || 653 (cons_str[len] == '"') || ISSPACE(cons_str[len])) && 654 (strncmp(cons_str, consolep->name, len) == 0)) { 655 console = consolep->value; 656 if (console == CONS_TTY) 657 tty_num = n; 658 break; 659 } 660 } 661 } 662 663 #if defined(__xpv) 664 /* 665 * domU's always use the hypervisor regardless of what 666 * the console variable may be set to. 667 */ 668 if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 669 console = CONS_HYPERVISOR; 670 console_hypervisor_redirect = B_TRUE; 671 } 672 #endif /* __xpv */ 673 674 /* 675 * If no console device specified, default to text. 676 * Remember what was specified for second phase. 677 */ 678 if (console == CONS_INVALID) 679 console = CONS_SCREEN_TEXT; 680 #if !defined(_BOOT) 681 else 682 console_set = 1; 683 #endif 684 685 #if defined(__xpv) 686 if (DOMAIN_IS_INITDOMAIN(xen_info)) { 687 switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) { 688 case XEN_CONSOLE_COM1: 689 case XEN_CONSOLE_COM2: 690 console_hypervisor_device = CONS_TTY; 691 console_hypervisor_tty_num = tty_num; 692 break; 693 case XEN_CONSOLE_VGA: 694 /* 695 * Currently xen doesn't really support 696 * keyboard/display console devices. 697 * What this setting means is that 698 * "vga=keep" has been enabled, which is 699 * more of a xen debugging tool that a 700 * true console mode. Hence, we're going 701 * to ignore this xen "console" setting. 702 */ 703 /*FALLTHROUGH*/ 704 default: 705 console_hypervisor_device = CONS_INVALID; 706 } 707 } 708 709 /* 710 * if the hypervisor is using the currently selected serial 711 * port then default to using the hypervisor as the console 712 * device. 713 */ 714 if (console == console_hypervisor_device) { 715 console = CONS_HYPERVISOR; 716 console_hypervisor_redirect = B_TRUE; 717 } 718 #endif /* __xpv */ 719 720 switch (console) { 721 case CONS_TTY: 722 serial_init(); 723 break; 724 725 case CONS_HYPERVISOR: 726 break; 727 728 #if !defined(_BOOT) 729 case CONS_USBSER: 730 /* 731 * We can't do anything with the usb serial 732 * until we have memory management. 733 */ 734 break; 735 #endif 736 case CONS_SCREEN_GRAPHICS: 737 kb_init(); 738 break; 739 case CONS_SCREEN_TEXT: 740 default: 741 #if defined(_BOOT) 742 clear_screen(); /* clears the grub or xen screen */ 743 #endif /* _BOOT */ 744 kb_init(); 745 break; 746 } 747 } 748 749 #if !defined(_BOOT) 750 /* 751 * 2nd part of console initialization. 752 * In the kernel (ie. fakebop), this can be used only to switch to 753 * using a serial port instead of screen based on the contents 754 * of the bootenv.rc file. 755 */ 756 /*ARGSUSED*/ 757 void 758 bcons_init2(char *inputdev, char *outputdev, char *consoledev) 759 { 760 int cons = CONS_INVALID; 761 int ttyn; 762 char *devnames[] = { consoledev, outputdev, inputdev, NULL }; 763 console_value_t *consolep; 764 int i; 765 extern int post_fastreboot; 766 767 if (post_fastreboot && console == CONS_SCREEN_GRAPHICS) 768 console = CONS_SCREEN_TEXT; 769 770 if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) { 771 if (console_set) { 772 /* 773 * If the console was set on the command line, 774 * but the ttyX-mode was not, we only need to 775 * check bootenv.rc for that setting. 776 */ 777 if ((!console_mode_set) && (console == CONS_TTY)) 778 serial_init(); 779 return; 780 } 781 782 for (i = 0; devnames[i] != NULL; i++) { 783 int n; 784 785 for (n = 0; console_devices[n].name != NULL; n++) { 786 consolep = &console_devices[n]; 787 if (strcmp(devnames[i], consolep->name) == 0) { 788 cons = consolep->value; 789 if (cons == CONS_TTY) 790 ttyn = n; 791 } 792 } 793 if (cons != CONS_INVALID) 794 break; 795 } 796 797 #if defined(__xpv) 798 /* 799 * if the hypervisor is using the currently selected console 800 * device then default to using the hypervisor as the console 801 * device. 802 */ 803 if (cons == console_hypervisor_device) { 804 cons = CONS_HYPERVISOR; 805 console_hypervisor_redirect = B_TRUE; 806 } 807 #endif /* __xpv */ 808 809 if ((cons == CONS_INVALID) || (cons == console)) { 810 /* 811 * we're sticking with whatever the current setting is 812 */ 813 return; 814 } 815 816 console = cons; 817 if (cons == CONS_TTY) { 818 tty_num = ttyn; 819 serial_init(); 820 return; 821 } 822 } else { 823 /* 824 * USB serial and GRAPHICS console 825 * we just collect data into a buffer 826 */ 827 extern void *defcons_init(size_t); 828 defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE); 829 } 830 } 831 832 #if defined(__xpv) 833 boolean_t 834 bcons_hypervisor_redirect(void) 835 { 836 return (console_hypervisor_redirect); 837 } 838 839 void 840 bcons_device_change(int new_console) 841 { 842 if (new_console < CONS_MIN || new_console > CONS_MAX) 843 return; 844 845 /* 846 * If we are asked to switch the console to the hypervisor, that 847 * really means to switch the console to whichever device the 848 * hypervisor is/was using. 849 */ 850 if (new_console == CONS_HYPERVISOR) 851 new_console = console_hypervisor_device; 852 853 console = new_console; 854 855 if (new_console == CONS_TTY) { 856 tty_num = console_hypervisor_tty_num; 857 serial_init(); 858 } 859 } 860 #endif /* __xpv */ 861 862 static void 863 defcons_putchar(int c) 864 { 865 if (defcons_buf != NULL && 866 defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) { 867 *defcons_cur++ = c; 868 *defcons_cur = 0; 869 } 870 } 871 #endif /* _BOOT */ 872 873 static void 874 serial_putchar(int c) 875 { 876 int checks = 10000; 877 878 while (((inb(port + LSR) & XHRE) == 0) && checks--) 879 ; 880 outb(port + DAT, (char)c); 881 } 882 883 static int 884 serial_getchar(void) 885 { 886 uchar_t lsr; 887 888 while (serial_ischar() == 0) 889 ; 890 891 lsr = inb(port + LSR); 892 if (lsr & (SERIAL_BREAK | SERIAL_FRAME | 893 SERIAL_PARITY | SERIAL_OVERRUN)) { 894 if (lsr & SERIAL_OVERRUN) { 895 return (inb(port + DAT)); 896 } else { 897 /* Toss the garbage */ 898 (void) inb(port + DAT); 899 return (0); 900 } 901 } 902 return (inb(port + DAT)); 903 } 904 905 static int 906 serial_ischar(void) 907 { 908 return (inb(port + LSR) & RCA); 909 } 910 911 static void 912 _doputchar(int c) 913 { 914 switch (console) { 915 case CONS_TTY: 916 serial_putchar(c); 917 return; 918 case CONS_SCREEN_TEXT: 919 screen_putchar(c); 920 return; 921 case CONS_SCREEN_GRAPHICS: 922 #if !defined(_BOOT) 923 case CONS_USBSER: 924 defcons_putchar(c); 925 #endif /* _BOOT */ 926 return; 927 } 928 } 929 930 void 931 bcons_putchar(int c) 932 { 933 static int bhcharpos = 0; 934 935 #if defined(__xpv) 936 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 937 console == CONS_HYPERVISOR) { 938 bcons_putchar_xen(c); 939 return; 940 } 941 #endif /* __xpv */ 942 943 if (c == '\t') { 944 do { 945 _doputchar(' '); 946 } while (++bhcharpos % 8); 947 return; 948 } else if (c == '\n' || c == '\r') { 949 bhcharpos = 0; 950 _doputchar('\r'); 951 _doputchar(c); 952 return; 953 } else if (c == '\b') { 954 if (bhcharpos) 955 bhcharpos--; 956 _doputchar(c); 957 return; 958 } 959 960 bhcharpos++; 961 _doputchar(c); 962 } 963 964 /* 965 * kernel character input functions 966 */ 967 int 968 bcons_getchar(void) 969 { 970 #if defined(__xpv) 971 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 972 console == CONS_HYPERVISOR) 973 return (bcons_getchar_xen()); 974 #endif /* __xpv */ 975 976 switch (console) { 977 case CONS_TTY: 978 return (serial_getchar()); 979 default: 980 return (kb_getchar()); 981 } 982 } 983 984 #if !defined(_BOOT) 985 986 int 987 bcons_ischar(void) 988 { 989 990 #if defined(__xpv) 991 if (!DOMAIN_IS_INITDOMAIN(xen_info) || 992 console == CONS_HYPERVISOR) 993 return (bcons_ischar_xen()); 994 #endif /* __xpv */ 995 996 switch (console) { 997 case CONS_TTY: 998 return (serial_ischar()); 999 default: 1000 return (kb_ischar()); 1001 } 1002 } 1003 1004 #endif /* _BOOT */ 1005