13446Smrj /* 23446Smrj * CDDL HEADER START 33446Smrj * 43446Smrj * The contents of this file are subject to the terms of the 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * You may not use this file except in compliance with the License. 73446Smrj * 83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93446Smrj * or http://www.opensolaris.org/os/licensing. 103446Smrj * See the License for the specific language governing permissions 113446Smrj * and limitations under the License. 123446Smrj * 133446Smrj * When distributing Covered Code, include this CDDL HEADER in each 143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153446Smrj * If applicable, add the following below this CDDL HEADER, with the 163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 183446Smrj * 193446Smrj * CDDL HEADER END 203446Smrj */ 213446Smrj /* 228960SJan.Setje-Eilers@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233446Smrj * Use is subject to license terms. 243446Smrj */ 253446Smrj 263446Smrj #include <sys/types.h> 273446Smrj #include <sys/systm.h> 283446Smrj #include <sys/archsystm.h> 293446Smrj #include <sys/boot_console.h> 305084Sjohnlev #include <sys/panic.h> 314088Srscott #include <sys/ctype.h> 325084Sjohnlev #if defined(__xpv) 335084Sjohnlev #include <sys/hypervisor.h> 345084Sjohnlev #endif /* __xpv */ 353446Smrj 363446Smrj #include "boot_serial.h" 373446Smrj #include "boot_vga.h" 383446Smrj 393446Smrj #if defined(_BOOT) 405084Sjohnlev #include <dboot/dboot_asm.h> 414088Srscott #include <dboot/dboot_xboot.h> 425084Sjohnlev #else /* _BOOT */ 433446Smrj #include <sys/bootconf.h> 445084Sjohnlev #if defined(__xpv) 455084Sjohnlev #include <sys/evtchn_impl.h> 465084Sjohnlev #endif /* __xpv */ 478960SJan.Setje-Eilers@Sun.COM static char *defcons_buf; 488960SJan.Setje-Eilers@Sun.COM static char *defcons_cur; 495084Sjohnlev #endif /* _BOOT */ 505084Sjohnlev 515084Sjohnlev #if defined(__xpv) 525084Sjohnlev extern void bcons_init_xen(char *); 535084Sjohnlev extern void bcons_putchar_xen(int); 545084Sjohnlev extern int bcons_getchar_xen(void); 555084Sjohnlev extern int bcons_ischar_xen(void); 565084Sjohnlev #endif /* __xpv */ 573446Smrj 583446Smrj static int cons_color = CONS_COLOR; 593446Smrj int console = CONS_SCREEN_TEXT; 605084Sjohnlev #if defined(__xpv) 615084Sjohnlev static int console_hypervisor_redirect = B_FALSE; 625084Sjohnlev static int console_hypervisor_device = CONS_INVALID; 635084Sjohnlev #endif /* __xpv */ 645084Sjohnlev 653446Smrj static int serial_ischar(void); 663446Smrj static int serial_getchar(void); 673446Smrj static void serial_putchar(int); 683446Smrj static void serial_adjust_prop(void); 693446Smrj 703446Smrj static char *boot_line = NULL; 713446Smrj 725084Sjohnlev #if !defined(_BOOT) 734088Srscott /* Set if the console or mode are expressed in the boot line */ 744088Srscott static int console_set, console_mode_set; 755084Sjohnlev #endif 764088Srscott 773446Smrj /* Clear the screen and initialize VIDEO, XPOS and YPOS. */ 785084Sjohnlev void 793446Smrj clear_screen(void) 803446Smrj { 813446Smrj /* 823446Smrj * XXX should set vga mode so we don't depend on the 835084Sjohnlev * state left by the boot loader. Note that we have to 845084Sjohnlev * enable the cursor before clearing the screen since 855084Sjohnlev * the cursor position is dependant upon the cursor 865084Sjohnlev * skew, which is initialized by vga_cursor_display() 873446Smrj */ 885084Sjohnlev vga_cursor_display(); 893446Smrj vga_clear(cons_color); 903446Smrj vga_setpos(0, 0); 913446Smrj } 923446Smrj 933446Smrj /* Put the character C on the screen. */ 943446Smrj static void 953446Smrj screen_putchar(int c) 963446Smrj { 973446Smrj int row, col; 983446Smrj 993446Smrj vga_getpos(&row, &col); 1003446Smrj switch (c) { 1013446Smrj case '\t': 1023446Smrj col += 8 - (col % 8); 1033446Smrj if (col == VGA_TEXT_COLS) 1043446Smrj col = 79; 1053446Smrj vga_setpos(row, col); 1063446Smrj break; 1073446Smrj 1083446Smrj case '\r': 1093446Smrj vga_setpos(row, 0); 1103446Smrj break; 1113446Smrj 1123446Smrj case '\b': 1133446Smrj if (col > 0) 1143446Smrj vga_setpos(row, col - 1); 1153446Smrj break; 1163446Smrj 1173446Smrj case '\n': 1183446Smrj if (row < VGA_TEXT_ROWS - 1) 1193446Smrj vga_setpos(row + 1, col); 1203446Smrj else 1213446Smrj vga_scroll(cons_color); 1223446Smrj break; 1233446Smrj 1243446Smrj default: 1253446Smrj vga_drawc(c, cons_color); 1263446Smrj if (col < VGA_TEXT_COLS -1) 1273446Smrj vga_setpos(row, col + 1); 1283446Smrj else if (row < VGA_TEXT_ROWS - 1) 1293446Smrj vga_setpos(row + 1, 0); 1303446Smrj else { 1313446Smrj vga_setpos(row, 0); 1323446Smrj vga_scroll(cons_color); 1333446Smrj } 1343446Smrj break; 1353446Smrj } 1363446Smrj } 1373446Smrj 1383446Smrj /* serial port stuff */ 1395084Sjohnlev #if defined(__xpv) && defined(_BOOT) 1405084Sjohnlev static int 1415084Sjohnlev ec_probe_pirq(int pirq) 1425084Sjohnlev { 1435084Sjohnlev evtchn_bind_pirq_t bind; 1445084Sjohnlev evtchn_close_t close; 1455084Sjohnlev 1465084Sjohnlev bind.pirq = pirq; 1475084Sjohnlev bind.flags = 0; 1485084Sjohnlev if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind) != 0) 1495084Sjohnlev return (0); 1505084Sjohnlev 1515084Sjohnlev close.port = bind.port; 1525084Sjohnlev (void) HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); 1535084Sjohnlev return (1); 1545084Sjohnlev } 1555084Sjohnlev #endif /* __xpv && _BOOT */ 1565084Sjohnlev 1573446Smrj static int port; 1583446Smrj 1593446Smrj static void 1603446Smrj serial_init(void) 1613446Smrj { 1623446Smrj switch (console) { 1633446Smrj case CONS_TTYA: 1643446Smrj port = 0x3f8; 1653446Smrj break; 1663446Smrj case CONS_TTYB: 1673446Smrj port = 0x2f8; 1683446Smrj break; 1693446Smrj } 1703446Smrj 1713446Smrj outb(port + ISR, 0x20); 1723446Smrj if (inb(port + ISR) & 0x20) { 1733446Smrj /* 1743446Smrj * 82510 chip is present 1753446Smrj */ 1763446Smrj outb(port + DAT+7, 0x04); /* clear status */ 1773446Smrj outb(port + ISR, 0x40); /* set to bank 2 */ 1783446Smrj outb(port + MCR, 0x08); /* IMD */ 1793446Smrj outb(port + DAT, 0x21); /* FMD */ 1803446Smrj outb(port + ISR, 0x00); /* set to bank 0 */ 1813446Smrj } else { 1823446Smrj /* 1833446Smrj * set the UART in FIFO mode if it has FIFO buffers. 1843446Smrj * use 16550 fifo reset sequence specified in NS 1853446Smrj * application note. disable fifos until chip is 1863446Smrj * initialized. 1873446Smrj */ 1883446Smrj outb(port + FIFOR, 0x00); /* clear */ 1893446Smrj outb(port + FIFOR, FIFO_ON); /* enable */ 1903446Smrj outb(port + FIFOR, FIFO_ON|FIFORXFLSH); /* reset */ 1913446Smrj outb(port + FIFOR, 1923446Smrj FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80); 1933446Smrj if ((inb(port + ISR) & 0xc0) != 0xc0) { 1943446Smrj /* 1953446Smrj * no fifo buffers so disable fifos. 1963446Smrj * this is true for 8250's 1973446Smrj */ 1983446Smrj outb(port + FIFOR, 0x00); 1993446Smrj } 2003446Smrj } 2013446Smrj 2023446Smrj /* disable interrupts */ 2033446Smrj outb(port + ICR, 0); 2043446Smrj 2055084Sjohnlev #if !defined(_BOOT) 2065084Sjohnlev if (IN_XPV_PANIC()) 2075084Sjohnlev return; 2085084Sjohnlev #endif 2095084Sjohnlev 2103446Smrj /* adjust setting based on tty properties */ 2113446Smrj serial_adjust_prop(); 2123446Smrj 2133446Smrj #if defined(_BOOT) 2143446Smrj /* 2153446Smrj * Do a full reset to match console behavior. 2163446Smrj * 0x1B + c - reset everything 2173446Smrj */ 2183446Smrj serial_putchar(0x1B); 2193446Smrj serial_putchar('c'); 2203446Smrj #endif 2213446Smrj } 2223446Smrj 2234088Srscott /* Advance str pointer past white space */ 2244088Srscott #define EAT_WHITE_SPACE(str) { \ 2254088Srscott while ((*str != '\0') && ISSPACE(*str)) \ 2264088Srscott str++; \ 2274088Srscott } 2284088Srscott 2294088Srscott /* 2304088Srscott * boot_line is set when we call here. Search it for the argument name, 2314088Srscott * and if found, return a pointer to it. 2324088Srscott */ 2334088Srscott static char * 2344088Srscott find_boot_line_prop(const char *name) 2354088Srscott { 2364088Srscott char *ptr; 2374088Srscott char end_char; 2384088Srscott size_t len; 2394088Srscott 2404088Srscott if (boot_line == NULL) 2414088Srscott return (NULL); 2424088Srscott 2434088Srscott len = strlen(name); 2444088Srscott 2454088Srscott /* 2464088Srscott * We have two nested loops here: the outer loop discards all options 2474088Srscott * except -B, and the inner loop parses the -B options looking for 2484088Srscott * the one we're interested in. 2494088Srscott */ 2504088Srscott for (ptr = boot_line; *ptr != '\0'; ptr++) { 2514088Srscott EAT_WHITE_SPACE(ptr); 2524088Srscott 2534088Srscott if (*ptr == '-') { 2544088Srscott ptr++; 2554088Srscott while ((*ptr != '\0') && (*ptr != 'B') && 2564088Srscott !ISSPACE(*ptr)) 2574088Srscott ptr++; 2584088Srscott if (*ptr == '\0') 2594088Srscott return (NULL); 2604088Srscott else if (*ptr != 'B') 2614088Srscott continue; 2624088Srscott } else { 2634088Srscott while ((*ptr != '\0') && !ISSPACE(*ptr)) 2644088Srscott ptr++; 2654088Srscott if (*ptr == '\0') 2664088Srscott return (NULL); 2674088Srscott continue; 2684088Srscott } 2694088Srscott 2704088Srscott do { 2714088Srscott ptr++; 2724088Srscott EAT_WHITE_SPACE(ptr); 2734088Srscott 2744088Srscott if ((strncmp(ptr, name, len) == 0) && 2754088Srscott (ptr[len] == '=')) { 2764088Srscott ptr += len + 1; 2774088Srscott if ((*ptr == '\'') || (*ptr == '"')) 2784088Srscott return (ptr + 1); 2794088Srscott else 2804088Srscott return (ptr); 2814088Srscott } 2824088Srscott 2834088Srscott /* 2844088Srscott * We have a property, and it's not the one we're 2854088Srscott * interested in. Skip the property name. A name 2864088Srscott * can end with '=', a comma, or white space. 2874088Srscott */ 2884088Srscott while ((*ptr != '\0') && (*ptr != '=') && 2894088Srscott (*ptr != ',') && (!ISSPACE(*ptr))) 2904088Srscott ptr++; 2914088Srscott 2924088Srscott /* 2934088Srscott * We only want to go through the rest of the inner 2944088Srscott * loop if we have a comma. If we have a property 2954088Srscott * name without a value, either continue or break. 2964088Srscott */ 2974088Srscott if (*ptr == '\0') 2984088Srscott return (NULL); 2994088Srscott else if (*ptr == ',') 3004088Srscott continue; 3014088Srscott else if (ISSPACE(*ptr)) 3024088Srscott break; 3034088Srscott ptr++; 3044088Srscott 3054088Srscott /* 3064088Srscott * Is the property quoted? 3074088Srscott */ 3084088Srscott if ((*ptr == '\'') || (*ptr == '"')) { 3094088Srscott end_char = *ptr; 3104088Srscott } else { 3114088Srscott /* 3124088Srscott * Not quoted, so the string ends at a comma 3134088Srscott * or at white space. Deal with white space 3144088Srscott * later. 3154088Srscott */ 3164088Srscott end_char = ','; 3174088Srscott } 3184088Srscott 3194088Srscott /* 3204088Srscott * Now, we can ignore any characters until we find 3214088Srscott * end_char. 3224088Srscott */ 3234088Srscott for (; (*ptr != '\0') && (*ptr != end_char); ptr++) { 3244088Srscott if ((end_char == ',') && ISSPACE(*ptr)) 3254088Srscott break; 3264088Srscott } 3274088Srscott if (*ptr && (*ptr != ',')) 3284088Srscott ptr++; 3294088Srscott } while (*ptr == ','); 3304088Srscott } 3314088Srscott return (NULL); 3324088Srscott } 3334088Srscott 3343446Smrj 3353446Smrj #define MATCHES(p, pat) \ 3363446Smrj (strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0) 3373446Smrj 3383446Smrj #define SKIP(p, c) \ 3393446Smrj while (*(p) != 0 && *p != (c)) \ 3403446Smrj ++(p); \ 3413446Smrj if (*(p) == (c)) \ 3423446Smrj ++(p); 3433446Smrj 3443446Smrj /* 3453446Smrj * find a tty mode property either from cmdline or from boot properties 3463446Smrj */ 3473446Smrj static char * 3483446Smrj get_mode_value(char *name) 3493446Smrj { 3503446Smrj /* 3513446Smrj * when specified on boot line it looks like "name" "=".... 3523446Smrj */ 3533446Smrj if (boot_line != NULL) { 3544088Srscott return (find_boot_line_prop(name)); 3553446Smrj } 3563446Smrj 3573446Smrj #if defined(_BOOT) 3583446Smrj return (NULL); 3593446Smrj #else 3603446Smrj /* 3613446Smrj * if we're running in the full kernel we check the bootenv.rc settings 3623446Smrj */ 3633446Smrj { 3643446Smrj static char propval[20]; 3653446Smrj 3663446Smrj propval[0] = 0; 3674088Srscott if (do_bsys_getproplen(NULL, name) <= 0) 3683446Smrj return (NULL); 3694088Srscott (void) do_bsys_getprop(NULL, name, propval); 3703446Smrj return (propval); 3713446Smrj } 3723446Smrj #endif 3733446Smrj } 3743446Smrj 3753446Smrj /* 3763446Smrj * adjust serial port based on properties 3773446Smrj * These come either from the cmdline or from boot properties. 3783446Smrj */ 3793446Smrj static void 3803446Smrj serial_adjust_prop(void) 3813446Smrj { 3823446Smrj char propname[20]; 3833446Smrj char *propval; 3843446Smrj char *p; 3853446Smrj ulong_t baud; 3863446Smrj uchar_t lcr = 0; 3873446Smrj uchar_t mcr = DTR | RTS; 3883446Smrj 3893446Smrj (void) strcpy(propname, "ttyX-mode"); 3903446Smrj propname[3] = 'a' + console - CONS_TTYA; 3913446Smrj propval = get_mode_value(propname); 3923446Smrj if (propval == NULL) 3933446Smrj propval = "9600,8,n,1,-"; 3945084Sjohnlev #if !defined(_BOOT) 3954088Srscott else 3964088Srscott console_mode_set = 1; 3975084Sjohnlev #endif 3983446Smrj 3993446Smrj /* property is of the form: "9600,8,n,1,-" */ 4003446Smrj p = propval; 4013446Smrj if (MATCHES(p, "110,")) 4023446Smrj baud = ASY110; 4033446Smrj else if (MATCHES(p, "150,")) 4043446Smrj baud = ASY150; 4053446Smrj else if (MATCHES(p, "300,")) 4063446Smrj baud = ASY300; 4073446Smrj else if (MATCHES(p, "600,")) 4083446Smrj baud = ASY600; 4093446Smrj else if (MATCHES(p, "1200,")) 4103446Smrj baud = ASY1200; 4113446Smrj else if (MATCHES(p, "2400,")) 4123446Smrj baud = ASY2400; 4133446Smrj else if (MATCHES(p, "4800,")) 4143446Smrj baud = ASY4800; 4153446Smrj else if (MATCHES(p, "19200,")) 4163446Smrj baud = ASY19200; 4173446Smrj else if (MATCHES(p, "38400,")) 4183446Smrj baud = ASY38400; 4193446Smrj else if (MATCHES(p, "57600,")) 4203446Smrj baud = ASY57600; 4213446Smrj else if (MATCHES(p, "115200,")) 4223446Smrj baud = ASY115200; 4233446Smrj else { 4243446Smrj baud = ASY9600; 4253446Smrj SKIP(p, ','); 4263446Smrj } 4273446Smrj outb(port + LCR, DLAB); 4283446Smrj outb(port + DAT + DLL, baud & 0xff); 4293446Smrj outb(port + DAT + DLH, (baud >> 8) & 0xff); 4303446Smrj 4313446Smrj switch (*p) { 4323446Smrj case '5': 4333446Smrj lcr |= BITS5; 4343446Smrj ++p; 4353446Smrj break; 4363446Smrj case '6': 4373446Smrj lcr |= BITS6; 4383446Smrj ++p; 4393446Smrj break; 4403446Smrj case '7': 4413446Smrj lcr |= BITS7; 4423446Smrj ++p; 4433446Smrj break; 4443446Smrj case '8': 4453446Smrj ++p; 4463446Smrj default: 4473446Smrj lcr |= BITS8; 4483446Smrj break; 4493446Smrj } 4503446Smrj 4513446Smrj SKIP(p, ','); 4523446Smrj 4533446Smrj switch (*p) { 4543446Smrj case 'n': 4553446Smrj lcr |= PARITY_NONE; 4563446Smrj ++p; 4573446Smrj break; 4583446Smrj case 'o': 4593446Smrj lcr |= PARITY_ODD; 4603446Smrj ++p; 4613446Smrj break; 4623446Smrj case 'e': 4633446Smrj ++p; 4643446Smrj default: 4653446Smrj lcr |= PARITY_EVEN; 4663446Smrj break; 4673446Smrj } 4683446Smrj 4693446Smrj 4703446Smrj SKIP(p, ','); 4713446Smrj 4723446Smrj switch (*p) { 4733446Smrj case '1': 4743446Smrj /* STOP1 is 0 */ 4753446Smrj ++p; 4763446Smrj break; 4773446Smrj default: 4783446Smrj lcr |= STOP2; 4793446Smrj break; 4803446Smrj } 4813446Smrj /* set parity bits */ 4823446Smrj outb(port + LCR, lcr); 4833446Smrj 4843446Smrj (void) strcpy(propname, "ttyX-rts-dtr-off"); 4853446Smrj propname[3] = 'a' + console - CONS_TTYA; 4863446Smrj propval = get_mode_value(propname); 4873446Smrj if (propval == NULL) 4883446Smrj propval = "false"; 4893446Smrj if (propval[0] != 'f' && propval[0] != 'F') 4903446Smrj mcr = 0; 4913446Smrj /* set modem control bits */ 4923446Smrj outb(port + MCR, mcr | OUT2); 4933446Smrj } 4943446Smrj 4954088Srscott /* 4964088Srscott * A structure to map console names to values. 4974088Srscott */ 4984088Srscott typedef struct { 4994088Srscott char *name; 5004088Srscott int value; 5014088Srscott } console_value_t; 5024088Srscott 5034088Srscott console_value_t console_devices[] = { 5044088Srscott { "ttya", CONS_TTYA }, 5054088Srscott { "ttyb", CONS_TTYB }, 5064088Srscott { "text", CONS_SCREEN_TEXT }, 5077701SJan.Setje-Eilers@Sun.COM { "graphics", CONS_SCREEN_GRAPHICS }, 5085084Sjohnlev #if defined(__xpv) 5095084Sjohnlev { "hypervisor", CONS_HYPERVISOR }, 5105084Sjohnlev #endif 5114088Srscott #if !defined(_BOOT) 5124088Srscott { "usb-serial", CONS_USBSER }, 5134088Srscott #endif 5144088Srscott { "", CONS_INVALID } 5154088Srscott }; 5164088Srscott 5173446Smrj void 5183446Smrj bcons_init(char *bootstr) 5193446Smrj { 5204088Srscott console_value_t *consolep; 5214088Srscott size_t len, cons_len; 5224088Srscott char *cons_str; 5234088Srscott 5243446Smrj boot_line = bootstr; 5253446Smrj console = CONS_INVALID; 5263446Smrj 5275084Sjohnlev #if defined(__xpv) 5285084Sjohnlev bcons_init_xen(bootstr); 5295084Sjohnlev #endif /* __xpv */ 5305084Sjohnlev 5314088Srscott cons_str = find_boot_line_prop("console"); 5324088Srscott if (cons_str == NULL) 5334088Srscott cons_str = find_boot_line_prop("output-device"); 5344088Srscott 5354088Srscott /* 5364088Srscott * Go through the console_devices array trying to match the string 5374088Srscott * we were given. The string on the command line must end with 5384088Srscott * a comma or white space. 5394088Srscott */ 5404088Srscott if (cons_str != NULL) { 5414088Srscott cons_len = strlen(cons_str); 5424088Srscott consolep = console_devices; 5434088Srscott for (; consolep->name[0] != '\0'; consolep++) { 5444088Srscott len = strlen(consolep->name); 5454088Srscott if ((len <= cons_len) && ((cons_str[len] == '\0') || 5464088Srscott (cons_str[len] == ',') || (cons_str[len] == '\'') || 5474088Srscott (cons_str[len] == '"') || ISSPACE(cons_str[len])) && 5484088Srscott (strncmp(cons_str, consolep->name, len) == 0)) { 5494088Srscott console = consolep->value; 5504088Srscott break; 5514088Srscott } 5524088Srscott } 5534088Srscott } 5543446Smrj 5555084Sjohnlev #if defined(__xpv) 5565084Sjohnlev /* 5575084Sjohnlev * domU's always use the hypervisor regardless of what 5585084Sjohnlev * the console variable may be set to. 5595084Sjohnlev */ 5605084Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 5615084Sjohnlev console = CONS_HYPERVISOR; 5625084Sjohnlev console_hypervisor_redirect = B_TRUE; 5635084Sjohnlev } 5645084Sjohnlev #endif /* __xpv */ 5655084Sjohnlev 5663446Smrj /* 5673446Smrj * If no console device specified, default to text. 5683446Smrj * Remember what was specified for second phase. 5693446Smrj */ 5703446Smrj if (console == CONS_INVALID) 5713446Smrj console = CONS_SCREEN_TEXT; 5725084Sjohnlev #if !defined(_BOOT) 5734088Srscott else 5744088Srscott console_set = 1; 5755084Sjohnlev #endif 5765084Sjohnlev 5775084Sjohnlev #if defined(__xpv) 5785084Sjohnlev if (DOMAIN_IS_INITDOMAIN(xen_info)) { 5795084Sjohnlev switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) { 5805084Sjohnlev case XEN_CONSOLE_COM1: 5815084Sjohnlev console_hypervisor_device = CONS_TTYA; 5825084Sjohnlev break; 5835084Sjohnlev case XEN_CONSOLE_COM2: 5845084Sjohnlev console_hypervisor_device = CONS_TTYB; 5855084Sjohnlev break; 5865084Sjohnlev case XEN_CONSOLE_VGA: 5875084Sjohnlev /* 5885084Sjohnlev * Currently xen doesn't really support 5895084Sjohnlev * keyboard/display console devices. 5905084Sjohnlev * What this setting means is that 5915084Sjohnlev * "vga=keep" has been enabled, which is 5925084Sjohnlev * more of a xen debugging tool that a 5935084Sjohnlev * true console mode. Hence, we're going 5945084Sjohnlev * to ignore this xen "console" setting. 5955084Sjohnlev */ 5965084Sjohnlev /*FALLTHROUGH*/ 5975084Sjohnlev default: 5985084Sjohnlev console_hypervisor_device = CONS_INVALID; 5995084Sjohnlev } 6005084Sjohnlev } 6015084Sjohnlev 6025084Sjohnlev /* 6035084Sjohnlev * if the hypervisor is using the currently selected serial 6045084Sjohnlev * port then default to using the hypervisor as the console 6055084Sjohnlev * device. 6065084Sjohnlev */ 6075084Sjohnlev if (console == console_hypervisor_device) { 6085084Sjohnlev console = CONS_HYPERVISOR; 6095084Sjohnlev console_hypervisor_redirect = B_TRUE; 6105084Sjohnlev } 6115084Sjohnlev #endif /* __xpv */ 6123446Smrj 6133446Smrj switch (console) { 6143446Smrj case CONS_TTYA: 6153446Smrj case CONS_TTYB: 6163446Smrj serial_init(); 6173446Smrj break; 6183446Smrj 6195084Sjohnlev case CONS_HYPERVISOR: 6205084Sjohnlev break; 6215084Sjohnlev 6224088Srscott #if !defined(_BOOT) 6234088Srscott case CONS_USBSER: 6244088Srscott /* 6254088Srscott * We can't do anything with the usb serial 6264088Srscott * until we have memory management. 6274088Srscott */ 6284088Srscott break; 6294088Srscott #endif 6307701SJan.Setje-Eilers@Sun.COM case CONS_SCREEN_GRAPHICS: 6317701SJan.Setje-Eilers@Sun.COM kb_init(); 6327701SJan.Setje-Eilers@Sun.COM break; 6333446Smrj case CONS_SCREEN_TEXT: 6343446Smrj default: 6353446Smrj #if defined(_BOOT) 6365084Sjohnlev clear_screen(); /* clears the grub or xen screen */ 6375084Sjohnlev #endif /* _BOOT */ 6383446Smrj kb_init(); 6393446Smrj break; 6403446Smrj } 6413446Smrj boot_line = NULL; 6423446Smrj } 6433446Smrj 6445084Sjohnlev #if !defined(_BOOT) 6453446Smrj /* 6463446Smrj * 2nd part of console initialization. 6473446Smrj * In the kernel (ie. fakebop), this can be used only to switch to 6483446Smrj * using a serial port instead of screen based on the contents 6493446Smrj * of the bootenv.rc file. 6503446Smrj */ 6513446Smrj /*ARGSUSED*/ 6523446Smrj void 6533446Smrj bcons_init2(char *inputdev, char *outputdev, char *consoledev) 6543446Smrj { 6553446Smrj int cons = CONS_INVALID; 6564088Srscott char *devnames[] = { consoledev, outputdev, inputdev, NULL }; 6574088Srscott console_value_t *consolep; 6584088Srscott int i; 6593446Smrj 6604088Srscott if (console != CONS_USBSER) { 6614088Srscott if (console_set) { 6624088Srscott /* 6634088Srscott * If the console was set on the command line, 6644088Srscott * but the ttyX-mode was not, we only need to 6654088Srscott * check bootenv.rc for that setting. 6664088Srscott */ 6674088Srscott if ((!console_mode_set) && 6684088Srscott (console == CONS_TTYA || console == CONS_TTYB)) 6694088Srscott serial_init(); 6704088Srscott return; 6714088Srscott } 6723446Smrj 6734088Srscott for (i = 0; devnames[i] != NULL; i++) { 6744088Srscott consolep = console_devices; 6754088Srscott for (; consolep->name[0] != '\0'; consolep++) { 6764088Srscott if (strcmp(devnames[i], consolep->name) == 0) { 6774088Srscott cons = consolep->value; 6784088Srscott } 6794088Srscott } 6804088Srscott if (cons != CONS_INVALID) 6814088Srscott break; 6824088Srscott } 6833446Smrj 6845084Sjohnlev #if defined(__xpv) 6855084Sjohnlev /* 6865084Sjohnlev * if the hypervisor is using the currently selected console 6875084Sjohnlev * device then default to using the hypervisor as the console 6885084Sjohnlev * device. 6895084Sjohnlev */ 6905084Sjohnlev if (cons == console_hypervisor_device) { 6915084Sjohnlev cons = CONS_HYPERVISOR; 6925084Sjohnlev console_hypervisor_redirect = B_TRUE; 6935084Sjohnlev } 6945084Sjohnlev #endif /* __xpv */ 6955084Sjohnlev 6965084Sjohnlev if ((cons == CONS_INVALID) || (cons == console)) { 6975084Sjohnlev /* 6985084Sjohnlev * we're sticking with whatever the current setting is 6995084Sjohnlev */ 7004088Srscott return; 7015084Sjohnlev } 7023446Smrj 7034088Srscott console = cons; 7044088Srscott if (cons == CONS_TTYA || cons == CONS_TTYB) { 7054088Srscott serial_init(); 7064088Srscott return; 7074088Srscott } 7083446Smrj } 7093446Smrj 7105084Sjohnlev 7113446Smrj /* 7123446Smrj * USB serial -- we just collect data into a buffer 7133446Smrj */ 7148960SJan.Setje-Eilers@Sun.COM if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) { 7158960SJan.Setje-Eilers@Sun.COM extern void *defcons_init(size_t); 7168960SJan.Setje-Eilers@Sun.COM defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE); 7173446Smrj } 7185084Sjohnlev } 7195084Sjohnlev 7205084Sjohnlev #if defined(__xpv) 7215084Sjohnlev boolean_t 7225084Sjohnlev bcons_hypervisor_redirect(void) 7235084Sjohnlev { 7245084Sjohnlev return (console_hypervisor_redirect); 7253446Smrj } 7263446Smrj 7275084Sjohnlev void 7285084Sjohnlev bcons_device_change(int new_console) 7295084Sjohnlev { 7305084Sjohnlev if (new_console < CONS_MIN || new_console > CONS_MAX) 7315084Sjohnlev return; 7325084Sjohnlev 7335084Sjohnlev /* 7345084Sjohnlev * If we are asked to switch the console to the hypervisor, that 7355084Sjohnlev * really means to switch the console to whichever device the 7365084Sjohnlev * hypervisor is/was using. 7375084Sjohnlev */ 7385084Sjohnlev if (new_console == CONS_HYPERVISOR) 7395084Sjohnlev new_console = console_hypervisor_device; 7405084Sjohnlev 7415084Sjohnlev console = new_console; 7425084Sjohnlev 7435084Sjohnlev if (new_console == CONS_TTYA || new_console == CONS_TTYB) 7445084Sjohnlev serial_init(); 7455084Sjohnlev } 7465084Sjohnlev #endif /* __xpv */ 7475084Sjohnlev 7483446Smrj static void 7498960SJan.Setje-Eilers@Sun.COM defcons_putchar(int c) 7503446Smrj { 751*9462SJan.Setje-Eilers@Sun.COM if (defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) { 7528960SJan.Setje-Eilers@Sun.COM *defcons_cur++ = c; 753*9462SJan.Setje-Eilers@Sun.COM *defcons_cur = 0; 754*9462SJan.Setje-Eilers@Sun.COM } 7553446Smrj } 7563446Smrj #endif /* _BOOT */ 7573446Smrj 7583446Smrj static void 7593446Smrj serial_putchar(int c) 7603446Smrj { 7613446Smrj int checks = 10000; 7623446Smrj 7633446Smrj while (((inb(port + LSR) & XHRE) == 0) && checks--) 7643446Smrj ; 7653446Smrj outb(port + DAT, (char)c); 7663446Smrj } 7673446Smrj 7683446Smrj static int 7693446Smrj serial_getchar(void) 7703446Smrj { 7713446Smrj uchar_t lsr; 7723446Smrj 7733446Smrj while (serial_ischar() == 0) 7743446Smrj ; 7753446Smrj 7763446Smrj lsr = inb(port + LSR); 7773446Smrj if (lsr & (SERIAL_BREAK | SERIAL_FRAME | 7783446Smrj SERIAL_PARITY | SERIAL_OVERRUN)) { 7793446Smrj if (lsr & SERIAL_OVERRUN) { 7803446Smrj return (inb(port + DAT)); 7813446Smrj } else { 7823446Smrj /* Toss the garbage */ 7833446Smrj (void) inb(port + DAT); 7843446Smrj return (0); 7853446Smrj } 7863446Smrj } 7873446Smrj return (inb(port + DAT)); 7883446Smrj } 7893446Smrj 7903446Smrj static int 7913446Smrj serial_ischar(void) 7923446Smrj { 7933446Smrj return (inb(port + LSR) & RCA); 7943446Smrj } 7953446Smrj 7963446Smrj static void 7973446Smrj _doputchar(int c) 7983446Smrj { 7993446Smrj switch (console) { 8003446Smrj case CONS_TTYA: 8013446Smrj case CONS_TTYB: 8023446Smrj serial_putchar(c); 8033446Smrj return; 8043446Smrj case CONS_SCREEN_TEXT: 8053446Smrj screen_putchar(c); 8063446Smrj return; 8077701SJan.Setje-Eilers@Sun.COM case CONS_SCREEN_GRAPHICS: 8083446Smrj #if !defined(_BOOT) 8093446Smrj case CONS_USBSER: 8108960SJan.Setje-Eilers@Sun.COM defcons_putchar(c); 8118960SJan.Setje-Eilers@Sun.COM #endif /* _BOOT */ 8123446Smrj return; 8133446Smrj } 8143446Smrj } 8153446Smrj 8163446Smrj void 8173446Smrj bcons_putchar(int c) 8183446Smrj { 8193446Smrj static int bhcharpos = 0; 8203446Smrj 8215084Sjohnlev #if defined(__xpv) 8225084Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info) || 8235084Sjohnlev console == CONS_HYPERVISOR) { 8245084Sjohnlev bcons_putchar_xen(c); 8255084Sjohnlev return; 8265084Sjohnlev } 8275084Sjohnlev #endif /* __xpv */ 8285084Sjohnlev 8293446Smrj if (c == '\t') { 8303446Smrj do { 8313446Smrj _doputchar(' '); 8323446Smrj } while (++bhcharpos % 8); 8333446Smrj return; 8343446Smrj } else if (c == '\n' || c == '\r') { 8353446Smrj bhcharpos = 0; 8363446Smrj _doputchar('\r'); 8373446Smrj _doputchar(c); 8383446Smrj return; 8393446Smrj } else if (c == '\b') { 8403446Smrj if (bhcharpos) 8413446Smrj bhcharpos--; 8423446Smrj _doputchar(c); 8433446Smrj return; 8443446Smrj } 8453446Smrj 8463446Smrj bhcharpos++; 8473446Smrj _doputchar(c); 8483446Smrj } 8493446Smrj 8503446Smrj /* 8513446Smrj * kernel character input functions 8523446Smrj */ 8533446Smrj int 8543446Smrj bcons_getchar(void) 8553446Smrj { 8565084Sjohnlev #if defined(__xpv) 8575084Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info) || 8585084Sjohnlev console == CONS_HYPERVISOR) 8595084Sjohnlev return (bcons_getchar_xen()); 8605084Sjohnlev #endif /* __xpv */ 8615084Sjohnlev 8623446Smrj switch (console) { 8633446Smrj case CONS_TTYA: 8643446Smrj case CONS_TTYB: 8653446Smrj return (serial_getchar()); 8663446Smrj default: 8673446Smrj return (kb_getchar()); 8683446Smrj } 8693446Smrj } 8703446Smrj 8713446Smrj #if !defined(_BOOT) 8723446Smrj 8733446Smrj int 8743446Smrj bcons_ischar(void) 8753446Smrj { 8765084Sjohnlev 8775084Sjohnlev #if defined(__xpv) 8785084Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info) || 8795084Sjohnlev console == CONS_HYPERVISOR) 8805084Sjohnlev return (bcons_ischar_xen()); 8815084Sjohnlev #endif /* __xpv */ 8825084Sjohnlev 8833446Smrj switch (console) { 8843446Smrj case CONS_TTYA: 8853446Smrj case CONS_TTYB: 8863446Smrj return (serial_ischar()); 8873446Smrj default: 8883446Smrj return (kb_ischar()); 8893446Smrj } 8903446Smrj } 8913446Smrj 8923446Smrj #endif /* _BOOT */ 893