xref: /onnv-gate/usr/src/uts/i86pc/boot/boot_console.c (revision 9462:2bd988026df0)
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