xref: /onnv-gate/usr/src/uts/i86pc/boot/boot_console.c (revision 10574:c8621ef15d56)
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;
6210175SStuart.Maybee@Sun.COM 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
clear_screen(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
screen_putchar(int c)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 static int port;
1393446Smrj 
1403446Smrj static void
serial_init(void)1413446Smrj serial_init(void)
1423446Smrj {
1433446Smrj 	switch (console) {
1443446Smrj 	case CONS_TTYA:
1453446Smrj 		port = 0x3f8;
1463446Smrj 		break;
1473446Smrj 	case CONS_TTYB:
1483446Smrj 		port = 0x2f8;
1493446Smrj 		break;
1503446Smrj 	}
1513446Smrj 
1523446Smrj 	outb(port + ISR, 0x20);
1533446Smrj 	if (inb(port + ISR) & 0x20) {
1543446Smrj 		/*
1553446Smrj 		 * 82510 chip is present
1563446Smrj 		 */
1573446Smrj 		outb(port + DAT+7, 0x04);	/* clear status */
1583446Smrj 		outb(port + ISR, 0x40);  /* set to bank 2 */
1593446Smrj 		outb(port + MCR, 0x08);  /* IMD */
1603446Smrj 		outb(port + DAT, 0x21);  /* FMD */
1613446Smrj 		outb(port + ISR, 0x00);  /* set to bank 0 */
1623446Smrj 	} else {
1633446Smrj 		/*
1643446Smrj 		 * set the UART in FIFO mode if it has FIFO buffers.
1653446Smrj 		 * use 16550 fifo reset sequence specified in NS
1663446Smrj 		 * application note. disable fifos until chip is
1673446Smrj 		 * initialized.
1683446Smrj 		 */
1693446Smrj 		outb(port + FIFOR, 0x00);		/* clear */
1703446Smrj 		outb(port + FIFOR, FIFO_ON);		/* enable */
1713446Smrj 		outb(port + FIFOR, FIFO_ON|FIFORXFLSH);  /* reset */
1723446Smrj 		outb(port + FIFOR,
1733446Smrj 		    FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80);
1743446Smrj 		if ((inb(port + ISR) & 0xc0) != 0xc0) {
1753446Smrj 			/*
1763446Smrj 			 * no fifo buffers so disable fifos.
1773446Smrj 			 * this is true for 8250's
1783446Smrj 			 */
1793446Smrj 			outb(port + FIFOR, 0x00);
1803446Smrj 		}
1813446Smrj 	}
1823446Smrj 
1833446Smrj 	/* disable interrupts */
1843446Smrj 	outb(port + ICR, 0);
1853446Smrj 
1865084Sjohnlev #if !defined(_BOOT)
1875084Sjohnlev 	if (IN_XPV_PANIC())
1885084Sjohnlev 		return;
1895084Sjohnlev #endif
1905084Sjohnlev 
1913446Smrj 	/* adjust setting based on tty properties */
1923446Smrj 	serial_adjust_prop();
1933446Smrj 
1943446Smrj #if defined(_BOOT)
1953446Smrj 	/*
1963446Smrj 	 * Do a full reset to match console behavior.
1973446Smrj 	 * 0x1B + c - reset everything
1983446Smrj 	 */
1993446Smrj 	serial_putchar(0x1B);
2003446Smrj 	serial_putchar('c');
2013446Smrj #endif
2023446Smrj }
2033446Smrj 
2044088Srscott /* Advance str pointer past white space */
2054088Srscott #define	EAT_WHITE_SPACE(str)	{			\
2064088Srscott 	while ((*str != '\0') && ISSPACE(*str))		\
2074088Srscott 		str++;					\
2084088Srscott }
2094088Srscott 
2104088Srscott /*
2114088Srscott  * boot_line is set when we call here.  Search it for the argument name,
2124088Srscott  * and if found, return a pointer to it.
2134088Srscott  */
2144088Srscott static char *
find_boot_line_prop(const char * name)2154088Srscott find_boot_line_prop(const char *name)
2164088Srscott {
2174088Srscott 	char *ptr;
21810092SEnrico.Perla@Sun.COM 	char *ret = NULL;
2194088Srscott 	char end_char;
2204088Srscott 	size_t len;
2214088Srscott 
2224088Srscott 	if (boot_line == NULL)
2234088Srscott 		return (NULL);
2244088Srscott 
2254088Srscott 	len = strlen(name);
2264088Srscott 
2274088Srscott 	/*
2284088Srscott 	 * We have two nested loops here: the outer loop discards all options
2294088Srscott 	 * except -B, and the inner loop parses the -B options looking for
2304088Srscott 	 * the one we're interested in.
2314088Srscott 	 */
2324088Srscott 	for (ptr = boot_line; *ptr != '\0'; ptr++) {
2334088Srscott 		EAT_WHITE_SPACE(ptr);
2344088Srscott 
2354088Srscott 		if (*ptr == '-') {
2364088Srscott 			ptr++;
2374088Srscott 			while ((*ptr != '\0') && (*ptr != 'B') &&
2384088Srscott 			    !ISSPACE(*ptr))
2394088Srscott 				ptr++;
2404088Srscott 			if (*ptr == '\0')
24110092SEnrico.Perla@Sun.COM 				goto out;
2424088Srscott 			else if (*ptr != 'B')
2434088Srscott 				continue;
2444088Srscott 		} else {
2454088Srscott 			while ((*ptr != '\0') && !ISSPACE(*ptr))
2464088Srscott 				ptr++;
2474088Srscott 			if (*ptr == '\0')
24810092SEnrico.Perla@Sun.COM 				goto out;
2494088Srscott 			continue;
2504088Srscott 		}
2514088Srscott 
2524088Srscott 		do {
2534088Srscott 			ptr++;
2544088Srscott 			EAT_WHITE_SPACE(ptr);
2554088Srscott 
2564088Srscott 			if ((strncmp(ptr, name, len) == 0) &&
2574088Srscott 			    (ptr[len] == '=')) {
2584088Srscott 				ptr += len + 1;
25910092SEnrico.Perla@Sun.COM 				if ((*ptr == '\'') || (*ptr == '"')) {
26010092SEnrico.Perla@Sun.COM 					ret = ptr + 1;
26110092SEnrico.Perla@Sun.COM 					end_char = *ptr;
26210092SEnrico.Perla@Sun.COM 					ptr++;
26310092SEnrico.Perla@Sun.COM 				} else {
26410092SEnrico.Perla@Sun.COM 					ret = ptr;
26510092SEnrico.Perla@Sun.COM 					end_char = ',';
26610092SEnrico.Perla@Sun.COM 				}
26710092SEnrico.Perla@Sun.COM 				goto consume_property;
2684088Srscott 			}
2694088Srscott 
2704088Srscott 			/*
2714088Srscott 			 * We have a property, and it's not the one we're
2724088Srscott 			 * interested in.  Skip the property name.  A name
2734088Srscott 			 * can end with '=', a comma, or white space.
2744088Srscott 			 */
2754088Srscott 			while ((*ptr != '\0') && (*ptr != '=') &&
2764088Srscott 			    (*ptr != ',') && (!ISSPACE(*ptr)))
2774088Srscott 				ptr++;
2784088Srscott 
2794088Srscott 			/*
2804088Srscott 			 * We only want to go through the rest of the inner
2814088Srscott 			 * loop if we have a comma.  If we have a property
2824088Srscott 			 * name without a value, either continue or break.
2834088Srscott 			 */
2844088Srscott 			if (*ptr == '\0')
28510092SEnrico.Perla@Sun.COM 				goto out;
2864088Srscott 			else if (*ptr == ',')
2874088Srscott 				continue;
2884088Srscott 			else if (ISSPACE(*ptr))
2894088Srscott 				break;
2904088Srscott 			ptr++;
2914088Srscott 
2924088Srscott 			/*
2934088Srscott 			 * Is the property quoted?
2944088Srscott 			 */
2954088Srscott 			if ((*ptr == '\'') || (*ptr == '"')) {
2964088Srscott 				end_char = *ptr;
29710092SEnrico.Perla@Sun.COM 				ptr++;
2984088Srscott 			} else {
2994088Srscott 				/*
3004088Srscott 				 * Not quoted, so the string ends at a comma
3014088Srscott 				 * or at white space.  Deal with white space
3024088Srscott 				 * later.
3034088Srscott 				 */
3044088Srscott 				end_char = ',';
3054088Srscott 			}
3064088Srscott 
3074088Srscott 			/*
3084088Srscott 			 * Now, we can ignore any characters until we find
3094088Srscott 			 * end_char.
3104088Srscott 			 */
31110092SEnrico.Perla@Sun.COM consume_property:
3124088Srscott 			for (; (*ptr != '\0') && (*ptr != end_char); ptr++) {
3134088Srscott 				if ((end_char == ',') && ISSPACE(*ptr))
3144088Srscott 					break;
3154088Srscott 			}
31610092SEnrico.Perla@Sun.COM 			if (*ptr && (*ptr != ',') && !ISSPACE(*ptr))
3174088Srscott 				ptr++;
3184088Srscott 		} while (*ptr == ',');
3194088Srscott 	}
32010092SEnrico.Perla@Sun.COM out:
32110092SEnrico.Perla@Sun.COM 	return (ret);
3224088Srscott }
3234088Srscott 
3243446Smrj 
3253446Smrj #define	MATCHES(p, pat)	\
3263446Smrj 	(strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0)
3273446Smrj 
3283446Smrj #define	SKIP(p, c)				\
3293446Smrj 	while (*(p) != 0 && *p != (c))		\
3303446Smrj 		++(p);				\
3313446Smrj 	if (*(p) == (c))			\
3323446Smrj 		++(p);
3333446Smrj 
3343446Smrj /*
3353446Smrj  * find a tty mode property either from cmdline or from boot properties
3363446Smrj  */
3373446Smrj static char *
get_mode_value(char * name)3383446Smrj get_mode_value(char *name)
3393446Smrj {
3403446Smrj 	/*
3413446Smrj 	 * when specified on boot line it looks like "name" "="....
3423446Smrj 	 */
3433446Smrj 	if (boot_line != NULL) {
3444088Srscott 		return (find_boot_line_prop(name));
3453446Smrj 	}
3463446Smrj 
3473446Smrj #if defined(_BOOT)
3483446Smrj 	return (NULL);
3493446Smrj #else
3503446Smrj 	/*
3513446Smrj 	 * if we're running in the full kernel we check the bootenv.rc settings
3523446Smrj 	 */
3533446Smrj 	{
3543446Smrj 		static char propval[20];
3553446Smrj 
3563446Smrj 		propval[0] = 0;
3574088Srscott 		if (do_bsys_getproplen(NULL, name) <= 0)
3583446Smrj 			return (NULL);
3594088Srscott 		(void) do_bsys_getprop(NULL, name, propval);
3603446Smrj 		return (propval);
3613446Smrj 	}
3623446Smrj #endif
3633446Smrj }
3643446Smrj 
3653446Smrj /*
3663446Smrj  * adjust serial port based on properties
3673446Smrj  * These come either from the cmdline or from boot properties.
3683446Smrj  */
3693446Smrj static void
serial_adjust_prop(void)3703446Smrj serial_adjust_prop(void)
3713446Smrj {
3723446Smrj 	char propname[20];
3733446Smrj 	char *propval;
3743446Smrj 	char *p;
3753446Smrj 	ulong_t baud;
3763446Smrj 	uchar_t lcr = 0;
3773446Smrj 	uchar_t mcr = DTR | RTS;
3783446Smrj 
3793446Smrj 	(void) strcpy(propname, "ttyX-mode");
3803446Smrj 	propname[3] = 'a' + console - CONS_TTYA;
3813446Smrj 	propval = get_mode_value(propname);
3823446Smrj 	if (propval == NULL)
3833446Smrj 		propval = "9600,8,n,1,-";
3845084Sjohnlev #if !defined(_BOOT)
3854088Srscott 	else
3864088Srscott 		console_mode_set = 1;
3875084Sjohnlev #endif
3883446Smrj 
3893446Smrj 	/* property is of the form: "9600,8,n,1,-" */
3903446Smrj 	p = propval;
3913446Smrj 	if (MATCHES(p, "110,"))
3923446Smrj 		baud = ASY110;
3933446Smrj 	else if (MATCHES(p, "150,"))
3943446Smrj 		baud = ASY150;
3953446Smrj 	else if (MATCHES(p, "300,"))
3963446Smrj 		baud = ASY300;
3973446Smrj 	else if (MATCHES(p, "600,"))
3983446Smrj 		baud = ASY600;
3993446Smrj 	else if (MATCHES(p, "1200,"))
4003446Smrj 		baud = ASY1200;
4013446Smrj 	else if (MATCHES(p, "2400,"))
4023446Smrj 		baud = ASY2400;
4033446Smrj 	else if (MATCHES(p, "4800,"))
4043446Smrj 		baud = ASY4800;
4053446Smrj 	else if (MATCHES(p, "19200,"))
4063446Smrj 		baud = ASY19200;
4073446Smrj 	else if (MATCHES(p, "38400,"))
4083446Smrj 		baud = ASY38400;
4093446Smrj 	else if (MATCHES(p, "57600,"))
4103446Smrj 		baud = ASY57600;
4113446Smrj 	else if (MATCHES(p, "115200,"))
4123446Smrj 		baud = ASY115200;
4133446Smrj 	else {
4143446Smrj 		baud = ASY9600;
4153446Smrj 		SKIP(p, ',');
4163446Smrj 	}
4173446Smrj 	outb(port + LCR, DLAB);
4183446Smrj 	outb(port + DAT + DLL, baud & 0xff);
4193446Smrj 	outb(port + DAT + DLH, (baud >> 8) & 0xff);
4203446Smrj 
4213446Smrj 	switch (*p) {
4223446Smrj 	case '5':
4233446Smrj 		lcr |= BITS5;
4243446Smrj 		++p;
4253446Smrj 		break;
4263446Smrj 	case '6':
4273446Smrj 		lcr |= BITS6;
4283446Smrj 		++p;
4293446Smrj 		break;
4303446Smrj 	case '7':
4313446Smrj 		lcr |= BITS7;
4323446Smrj 		++p;
4333446Smrj 		break;
4343446Smrj 	case '8':
4353446Smrj 		++p;
4363446Smrj 	default:
4373446Smrj 		lcr |= BITS8;
4383446Smrj 		break;
4393446Smrj 	}
4403446Smrj 
4413446Smrj 	SKIP(p, ',');
4423446Smrj 
4433446Smrj 	switch (*p) {
4443446Smrj 	case 'n':
4453446Smrj 		lcr |= PARITY_NONE;
4463446Smrj 		++p;
4473446Smrj 		break;
4483446Smrj 	case 'o':
4493446Smrj 		lcr |= PARITY_ODD;
4503446Smrj 		++p;
4513446Smrj 		break;
4523446Smrj 	case 'e':
4533446Smrj 		++p;
4543446Smrj 	default:
4553446Smrj 		lcr |= PARITY_EVEN;
4563446Smrj 		break;
4573446Smrj 	}
4583446Smrj 
4593446Smrj 
4603446Smrj 	SKIP(p, ',');
4613446Smrj 
4623446Smrj 	switch (*p) {
4633446Smrj 	case '1':
4643446Smrj 		/* STOP1 is 0 */
4653446Smrj 		++p;
4663446Smrj 		break;
4673446Smrj 	default:
4683446Smrj 		lcr |= STOP2;
4693446Smrj 		break;
4703446Smrj 	}
4713446Smrj 	/* set parity bits */
4723446Smrj 	outb(port + LCR, lcr);
4733446Smrj 
4743446Smrj 	(void) strcpy(propname, "ttyX-rts-dtr-off");
4753446Smrj 	propname[3] = 'a' + console - CONS_TTYA;
4763446Smrj 	propval = get_mode_value(propname);
4773446Smrj 	if (propval == NULL)
4783446Smrj 		propval = "false";
4793446Smrj 	if (propval[0] != 'f' && propval[0] != 'F')
4803446Smrj 		mcr = 0;
4813446Smrj 	/* set modem control bits */
4823446Smrj 	outb(port + MCR, mcr | OUT2);
4833446Smrj }
4843446Smrj 
4854088Srscott /*
4864088Srscott  * A structure to map console names to values.
4874088Srscott  */
4884088Srscott typedef struct {
4894088Srscott 	char *name;
4904088Srscott 	int value;
4914088Srscott } console_value_t;
4924088Srscott 
4934088Srscott console_value_t console_devices[] = {
4944088Srscott 	{ "ttya", CONS_TTYA },
4954088Srscott 	{ "ttyb", CONS_TTYB },
4964088Srscott 	{ "text", CONS_SCREEN_TEXT },
4977701SJan.Setje-Eilers@Sun.COM 	{ "graphics", CONS_SCREEN_GRAPHICS },
4985084Sjohnlev #if defined(__xpv)
4995084Sjohnlev 	{ "hypervisor", CONS_HYPERVISOR },
5005084Sjohnlev #endif
5014088Srscott #if !defined(_BOOT)
5024088Srscott 	{ "usb-serial", CONS_USBSER },
5034088Srscott #endif
5044088Srscott 	{ "", CONS_INVALID }
5054088Srscott };
5064088Srscott 
5073446Smrj void
bcons_init(char * bootstr)5083446Smrj bcons_init(char *bootstr)
5093446Smrj {
5104088Srscott 	console_value_t *consolep;
5114088Srscott 	size_t len, cons_len;
5124088Srscott 	char *cons_str;
513*10574SSherry.Moore@Sun.COM #if !defined(_BOOT)
514*10574SSherry.Moore@Sun.COM 	static char console_text[] = "text";
515*10574SSherry.Moore@Sun.COM 	extern int post_fastreboot;
516*10574SSherry.Moore@Sun.COM #endif
5174088Srscott 
5183446Smrj 	boot_line = bootstr;
5193446Smrj 	console = CONS_INVALID;
5203446Smrj 
5215084Sjohnlev #if defined(__xpv)
5225084Sjohnlev 	bcons_init_xen(bootstr);
5235084Sjohnlev #endif /* __xpv */
5245084Sjohnlev 
5254088Srscott 	cons_str = find_boot_line_prop("console");
5264088Srscott 	if (cons_str == NULL)
5274088Srscott 		cons_str = find_boot_line_prop("output-device");
5284088Srscott 
529*10574SSherry.Moore@Sun.COM #if !defined(_BOOT)
530*10574SSherry.Moore@Sun.COM 	if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
531*10574SSherry.Moore@Sun.COM 		cons_str = console_text;
532*10574SSherry.Moore@Sun.COM #endif
533*10574SSherry.Moore@Sun.COM 
5344088Srscott 	/*
5354088Srscott 	 * Go through the console_devices array trying to match the string
5364088Srscott 	 * we were given.  The string on the command line must end with
5374088Srscott 	 * a comma or white space.
5384088Srscott 	 */
5394088Srscott 	if (cons_str != NULL) {
5404088Srscott 		cons_len = strlen(cons_str);
5414088Srscott 		consolep = console_devices;
5424088Srscott 		for (; consolep->name[0] != '\0'; consolep++) {
5434088Srscott 			len = strlen(consolep->name);
5444088Srscott 			if ((len <= cons_len) && ((cons_str[len] == '\0') ||
5454088Srscott 			    (cons_str[len] == ',') || (cons_str[len] == '\'') ||
5464088Srscott 			    (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
5474088Srscott 			    (strncmp(cons_str, consolep->name, len) == 0)) {
5484088Srscott 				console = consolep->value;
5494088Srscott 				break;
5504088Srscott 			}
5514088Srscott 		}
5524088Srscott 	}
5533446Smrj 
5545084Sjohnlev #if defined(__xpv)
5555084Sjohnlev 	/*
5565084Sjohnlev 	 * domU's always use the hypervisor regardless of what
5575084Sjohnlev 	 * the console variable may be set to.
5585084Sjohnlev 	 */
5595084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
5605084Sjohnlev 		console = CONS_HYPERVISOR;
5615084Sjohnlev 		console_hypervisor_redirect = B_TRUE;
5625084Sjohnlev 	}
5635084Sjohnlev #endif /* __xpv */
5645084Sjohnlev 
5653446Smrj 	/*
5663446Smrj 	 * If no console device specified, default to text.
5673446Smrj 	 * Remember what was specified for second phase.
5683446Smrj 	 */
5693446Smrj 	if (console == CONS_INVALID)
5703446Smrj 		console = CONS_SCREEN_TEXT;
5715084Sjohnlev #if !defined(_BOOT)
5724088Srscott 	else
5734088Srscott 		console_set = 1;
5745084Sjohnlev #endif
5755084Sjohnlev 
5765084Sjohnlev #if defined(__xpv)
5775084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
5785084Sjohnlev 		switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) {
5795084Sjohnlev 			case XEN_CONSOLE_COM1:
5805084Sjohnlev 				console_hypervisor_device = CONS_TTYA;
5815084Sjohnlev 				break;
5825084Sjohnlev 			case XEN_CONSOLE_COM2:
5835084Sjohnlev 				console_hypervisor_device = CONS_TTYB;
5845084Sjohnlev 				break;
5855084Sjohnlev 			case XEN_CONSOLE_VGA:
5865084Sjohnlev 				/*
5875084Sjohnlev 				 * Currently xen doesn't really support
5885084Sjohnlev 				 * keyboard/display console devices.
5895084Sjohnlev 				 * What this setting means is that
5905084Sjohnlev 				 * "vga=keep" has been enabled, which is
5915084Sjohnlev 				 * more of a xen debugging tool that a
5925084Sjohnlev 				 * true console mode.  Hence, we're going
5935084Sjohnlev 				 * to ignore this xen "console" setting.
5945084Sjohnlev 				 */
5955084Sjohnlev 				/*FALLTHROUGH*/
5965084Sjohnlev 			default:
5975084Sjohnlev 				console_hypervisor_device = CONS_INVALID;
5985084Sjohnlev 		}
5995084Sjohnlev 	}
6005084Sjohnlev 
6015084Sjohnlev 	/*
6025084Sjohnlev 	 * if the hypervisor is using the currently selected serial
6035084Sjohnlev 	 * port then default to using the hypervisor as the console
6045084Sjohnlev 	 * device.
6055084Sjohnlev 	 */
6065084Sjohnlev 	if (console == console_hypervisor_device) {
6075084Sjohnlev 		console = CONS_HYPERVISOR;
6085084Sjohnlev 		console_hypervisor_redirect = B_TRUE;
6095084Sjohnlev 	}
6105084Sjohnlev #endif /* __xpv */
6113446Smrj 
6123446Smrj 	switch (console) {
6133446Smrj 	case CONS_TTYA:
6143446Smrj 	case CONS_TTYB:
6153446Smrj 		serial_init();
6163446Smrj 		break;
6173446Smrj 
6185084Sjohnlev 	case CONS_HYPERVISOR:
6195084Sjohnlev 		break;
6205084Sjohnlev 
6214088Srscott #if !defined(_BOOT)
6224088Srscott 	case CONS_USBSER:
6234088Srscott 		/*
6244088Srscott 		 * We can't do anything with the usb serial
6254088Srscott 		 * until we have memory management.
6264088Srscott 		 */
6274088Srscott 		break;
6284088Srscott #endif
6297701SJan.Setje-Eilers@Sun.COM 	case CONS_SCREEN_GRAPHICS:
6307701SJan.Setje-Eilers@Sun.COM 		kb_init();
6317701SJan.Setje-Eilers@Sun.COM 		break;
6323446Smrj 	case CONS_SCREEN_TEXT:
6333446Smrj 	default:
6343446Smrj #if defined(_BOOT)
6355084Sjohnlev 		clear_screen();	/* clears the grub or xen screen */
6365084Sjohnlev #endif /* _BOOT */
6373446Smrj 		kb_init();
6383446Smrj 		break;
6393446Smrj 	}
6403446Smrj 	boot_line = NULL;
6413446Smrj }
6423446Smrj 
6435084Sjohnlev #if !defined(_BOOT)
6443446Smrj /*
6453446Smrj  * 2nd part of console initialization.
6463446Smrj  * In the kernel (ie. fakebop), this can be used only to switch to
6473446Smrj  * using a serial port instead of screen based on the contents
6483446Smrj  * of the bootenv.rc file.
6493446Smrj  */
6503446Smrj /*ARGSUSED*/
6513446Smrj void
bcons_init2(char * inputdev,char * outputdev,char * consoledev)6523446Smrj bcons_init2(char *inputdev, char *outputdev, char *consoledev)
6533446Smrj {
6543446Smrj 	int cons = CONS_INVALID;
6554088Srscott 	char *devnames[] = { consoledev, outputdev, inputdev, NULL };
6564088Srscott 	console_value_t *consolep;
6574088Srscott 	int i;
658*10574SSherry.Moore@Sun.COM 	extern int post_fastreboot;
659*10574SSherry.Moore@Sun.COM 
660*10574SSherry.Moore@Sun.COM 	if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
661*10574SSherry.Moore@Sun.COM 		console = CONS_SCREEN_TEXT;
6623446Smrj 
66310092SEnrico.Perla@Sun.COM 	if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) {
6644088Srscott 		if (console_set) {
6654088Srscott 			/*
6664088Srscott 			 * If the console was set on the command line,
6674088Srscott 			 * but the ttyX-mode was not, we only need to
6684088Srscott 			 * check bootenv.rc for that setting.
6694088Srscott 			 */
6704088Srscott 			if ((!console_mode_set) &&
6714088Srscott 			    (console == CONS_TTYA || console == CONS_TTYB))
6724088Srscott 				serial_init();
6734088Srscott 			return;
6744088Srscott 		}
6753446Smrj 
6764088Srscott 		for (i = 0; devnames[i] != NULL; i++) {
6774088Srscott 			consolep = console_devices;
6784088Srscott 			for (; consolep->name[0] != '\0'; consolep++) {
6794088Srscott 				if (strcmp(devnames[i], consolep->name) == 0) {
6804088Srscott 					cons = consolep->value;
6814088Srscott 				}
6824088Srscott 			}
6834088Srscott 			if (cons != CONS_INVALID)
6844088Srscott 				break;
6854088Srscott 		}
6863446Smrj 
6875084Sjohnlev #if defined(__xpv)
6885084Sjohnlev 		/*
6895084Sjohnlev 		 * if the hypervisor is using the currently selected console
6905084Sjohnlev 		 * device then default to using the hypervisor as the console
6915084Sjohnlev 		 * device.
6925084Sjohnlev 		 */
6935084Sjohnlev 		if (cons == console_hypervisor_device) {
6945084Sjohnlev 			cons = CONS_HYPERVISOR;
6955084Sjohnlev 			console_hypervisor_redirect = B_TRUE;
6965084Sjohnlev 		}
6975084Sjohnlev #endif /* __xpv */
6985084Sjohnlev 
6995084Sjohnlev 		if ((cons == CONS_INVALID) || (cons == console)) {
7005084Sjohnlev 			/*
7015084Sjohnlev 			 * we're sticking with whatever the current setting is
7025084Sjohnlev 			 */
7034088Srscott 			return;
7045084Sjohnlev 		}
7053446Smrj 
7064088Srscott 		console = cons;
7074088Srscott 		if (cons == CONS_TTYA || cons == CONS_TTYB) {
7084088Srscott 			serial_init();
7094088Srscott 			return;
7104088Srscott 		}
71110092SEnrico.Perla@Sun.COM 	} else {
71210092SEnrico.Perla@Sun.COM 		/*
71310092SEnrico.Perla@Sun.COM 		 * USB serial and GRAPHICS console
71410092SEnrico.Perla@Sun.COM 		 * we just collect data into a buffer
71510092SEnrico.Perla@Sun.COM 		 */
7168960SJan.Setje-Eilers@Sun.COM 		extern void *defcons_init(size_t);
7178960SJan.Setje-Eilers@Sun.COM 		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
7183446Smrj 	}
7195084Sjohnlev }
7205084Sjohnlev 
7215084Sjohnlev #if defined(__xpv)
7225084Sjohnlev boolean_t
bcons_hypervisor_redirect(void)7235084Sjohnlev bcons_hypervisor_redirect(void)
7245084Sjohnlev {
7255084Sjohnlev 	return (console_hypervisor_redirect);
7263446Smrj }
7273446Smrj 
7285084Sjohnlev void
bcons_device_change(int new_console)7295084Sjohnlev bcons_device_change(int new_console)
7305084Sjohnlev {
7315084Sjohnlev 	if (new_console < CONS_MIN || new_console > CONS_MAX)
7325084Sjohnlev 		return;
7335084Sjohnlev 
7345084Sjohnlev 	/*
7355084Sjohnlev 	 * If we are asked to switch the console to the hypervisor, that
7365084Sjohnlev 	 * really means to switch the console to whichever device the
7375084Sjohnlev 	 * hypervisor is/was using.
7385084Sjohnlev 	 */
7395084Sjohnlev 	if (new_console == CONS_HYPERVISOR)
7405084Sjohnlev 		new_console = console_hypervisor_device;
7415084Sjohnlev 
7425084Sjohnlev 	console = new_console;
7435084Sjohnlev 
7445084Sjohnlev 	if (new_console == CONS_TTYA || new_console == CONS_TTYB)
7455084Sjohnlev 		serial_init();
7465084Sjohnlev }
7475084Sjohnlev #endif /* __xpv */
7485084Sjohnlev 
7493446Smrj static void
defcons_putchar(int c)7508960SJan.Setje-Eilers@Sun.COM defcons_putchar(int c)
7513446Smrj {
75210092SEnrico.Perla@Sun.COM 	if (defcons_buf != NULL &&
75310092SEnrico.Perla@Sun.COM 	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
7548960SJan.Setje-Eilers@Sun.COM 		*defcons_cur++ = c;
7559462SJan.Setje-Eilers@Sun.COM 		*defcons_cur = 0;
7569462SJan.Setje-Eilers@Sun.COM 	}
7573446Smrj }
7583446Smrj #endif	/* _BOOT */
7593446Smrj 
7603446Smrj static void
serial_putchar(int c)7613446Smrj serial_putchar(int c)
7623446Smrj {
7633446Smrj 	int checks = 10000;
7643446Smrj 
7653446Smrj 	while (((inb(port + LSR) & XHRE) == 0) && checks--)
7663446Smrj 		;
7673446Smrj 	outb(port + DAT, (char)c);
7683446Smrj }
7693446Smrj 
7703446Smrj static int
serial_getchar(void)7713446Smrj serial_getchar(void)
7723446Smrj {
7733446Smrj 	uchar_t lsr;
7743446Smrj 
7753446Smrj 	while (serial_ischar() == 0)
7763446Smrj 		;
7773446Smrj 
7783446Smrj 	lsr = inb(port + LSR);
7793446Smrj 	if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
7803446Smrj 	    SERIAL_PARITY | SERIAL_OVERRUN)) {
7813446Smrj 		if (lsr & SERIAL_OVERRUN) {
7823446Smrj 			return (inb(port + DAT));
7833446Smrj 		} else {
7843446Smrj 			/* Toss the garbage */
7853446Smrj 			(void) inb(port + DAT);
7863446Smrj 			return (0);
7873446Smrj 		}
7883446Smrj 	}
7893446Smrj 	return (inb(port + DAT));
7903446Smrj }
7913446Smrj 
7923446Smrj static int
serial_ischar(void)7933446Smrj serial_ischar(void)
7943446Smrj {
7953446Smrj 	return (inb(port + LSR) & RCA);
7963446Smrj }
7973446Smrj 
7983446Smrj static void
_doputchar(int c)7993446Smrj _doputchar(int c)
8003446Smrj {
8013446Smrj 	switch (console) {
8023446Smrj 	case CONS_TTYA:
8033446Smrj 	case CONS_TTYB:
8043446Smrj 		serial_putchar(c);
8053446Smrj 		return;
8063446Smrj 	case CONS_SCREEN_TEXT:
8073446Smrj 		screen_putchar(c);
8083446Smrj 		return;
8097701SJan.Setje-Eilers@Sun.COM 	case CONS_SCREEN_GRAPHICS:
8103446Smrj #if !defined(_BOOT)
8113446Smrj 	case CONS_USBSER:
8128960SJan.Setje-Eilers@Sun.COM 		defcons_putchar(c);
8138960SJan.Setje-Eilers@Sun.COM #endif /* _BOOT */
8143446Smrj 		return;
8153446Smrj 	}
8163446Smrj }
8173446Smrj 
8183446Smrj void
bcons_putchar(int c)8193446Smrj bcons_putchar(int c)
8203446Smrj {
8213446Smrj 	static int bhcharpos = 0;
8223446Smrj 
8235084Sjohnlev #if defined(__xpv)
8245084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
8255084Sjohnlev 	    console == CONS_HYPERVISOR) {
8265084Sjohnlev 		bcons_putchar_xen(c);
8275084Sjohnlev 		return;
8285084Sjohnlev 	}
8295084Sjohnlev #endif /* __xpv */
8305084Sjohnlev 
8313446Smrj 	if (c == '\t') {
8323446Smrj 		do {
8333446Smrj 			_doputchar(' ');
8343446Smrj 		} while (++bhcharpos % 8);
8353446Smrj 		return;
8363446Smrj 	} else  if (c == '\n' || c == '\r') {
8373446Smrj 		bhcharpos = 0;
8383446Smrj 		_doputchar('\r');
8393446Smrj 		_doputchar(c);
8403446Smrj 		return;
8413446Smrj 	} else if (c == '\b') {
8423446Smrj 		if (bhcharpos)
8433446Smrj 			bhcharpos--;
8443446Smrj 		_doputchar(c);
8453446Smrj 		return;
8463446Smrj 	}
8473446Smrj 
8483446Smrj 	bhcharpos++;
8493446Smrj 	_doputchar(c);
8503446Smrj }
8513446Smrj 
8523446Smrj /*
8533446Smrj  * kernel character input functions
8543446Smrj  */
8553446Smrj int
bcons_getchar(void)8563446Smrj bcons_getchar(void)
8573446Smrj {
8585084Sjohnlev #if defined(__xpv)
8595084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
8605084Sjohnlev 	    console == CONS_HYPERVISOR)
8615084Sjohnlev 		return (bcons_getchar_xen());
8625084Sjohnlev #endif /* __xpv */
8635084Sjohnlev 
8643446Smrj 	switch (console) {
8653446Smrj 	case CONS_TTYA:
8663446Smrj 	case CONS_TTYB:
8673446Smrj 		return (serial_getchar());
8683446Smrj 	default:
8693446Smrj 		return (kb_getchar());
8703446Smrj 	}
8713446Smrj }
8723446Smrj 
8733446Smrj #if !defined(_BOOT)
8743446Smrj 
8753446Smrj int
bcons_ischar(void)8763446Smrj bcons_ischar(void)
8773446Smrj {
8785084Sjohnlev 
8795084Sjohnlev #if defined(__xpv)
8805084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
8815084Sjohnlev 	    console == CONS_HYPERVISOR)
8825084Sjohnlev 		return (bcons_ischar_xen());
8835084Sjohnlev #endif /* __xpv */
8845084Sjohnlev 
8853446Smrj 	switch (console) {
8863446Smrj 	case CONS_TTYA:
8873446Smrj 	case CONS_TTYB:
8883446Smrj 		return (serial_ischar());
8893446Smrj 	default:
8903446Smrj 		return (kb_ischar());
8913446Smrj 	}
8923446Smrj }
8933446Smrj 
8943446Smrj #endif /* _BOOT */
895