xref: /titanic_51/usr/src/uts/i86pc/boot/boot_console.c (revision b9a8673242dc0b7f31f1f654e8234d6d11bcfa20)
1ae115bc7Smrj /*
2ae115bc7Smrj  * CDDL HEADER START
3ae115bc7Smrj  *
4ae115bc7Smrj  * The contents of this file are subject to the terms of the
5ae115bc7Smrj  * Common Development and Distribution License (the "License").
6ae115bc7Smrj  * You may not use this file except in compliance with the License.
7ae115bc7Smrj  *
8ae115bc7Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ae115bc7Smrj  * or http://www.opensolaris.org/os/licensing.
10ae115bc7Smrj  * See the License for the specific language governing permissions
11ae115bc7Smrj  * and limitations under the License.
12ae115bc7Smrj  *
13ae115bc7Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14ae115bc7Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ae115bc7Smrj  * If applicable, add the following below this CDDL HEADER, with the
16ae115bc7Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17ae115bc7Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18ae115bc7Smrj  *
19ae115bc7Smrj  * CDDL HEADER END
20ae115bc7Smrj  */
21ae115bc7Smrj /*
220d928757SGary Mills  * Copyright (c) 2012 Gary Mills
230d928757SGary Mills  *
2448633f18SJan Setje-Eilers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25ae115bc7Smrj  * Use is subject to license terms.
26ae115bc7Smrj  */
27ae115bc7Smrj 
28ae115bc7Smrj #include <sys/types.h>
29ae115bc7Smrj #include <sys/systm.h>
30ae115bc7Smrj #include <sys/archsystm.h>
31ae115bc7Smrj #include <sys/boot_console.h>
32843e1988Sjohnlev #include <sys/panic.h>
33adb91f47Srscott #include <sys/ctype.h>
34843e1988Sjohnlev #if defined(__xpv)
35843e1988Sjohnlev #include <sys/hypervisor.h>
36843e1988Sjohnlev #endif /* __xpv */
37ae115bc7Smrj 
38ae115bc7Smrj #include "boot_serial.h"
39ae115bc7Smrj #include "boot_vga.h"
40ae115bc7Smrj 
41ae115bc7Smrj #if defined(_BOOT)
42843e1988Sjohnlev #include <dboot/dboot_asm.h>
43adb91f47Srscott #include <dboot/dboot_xboot.h>
44843e1988Sjohnlev #else /* _BOOT */
45ae115bc7Smrj #include <sys/bootconf.h>
46843e1988Sjohnlev #if defined(__xpv)
47843e1988Sjohnlev #include <sys/evtchn_impl.h>
48843e1988Sjohnlev #endif /* __xpv */
4948633f18SJan Setje-Eilers static char *defcons_buf;
5048633f18SJan Setje-Eilers static char *defcons_cur;
51843e1988Sjohnlev #endif /* _BOOT */
52843e1988Sjohnlev 
53843e1988Sjohnlev #if defined(__xpv)
54843e1988Sjohnlev extern void bcons_init_xen(char *);
55843e1988Sjohnlev extern void bcons_putchar_xen(int);
56843e1988Sjohnlev extern int bcons_getchar_xen(void);
57843e1988Sjohnlev extern int bcons_ischar_xen(void);
58843e1988Sjohnlev #endif /* __xpv */
59ae115bc7Smrj 
60ae115bc7Smrj static int cons_color = CONS_COLOR;
610d928757SGary Mills static int console = CONS_SCREEN_TEXT;
620d928757SGary Mills static int tty_num = 0;
630d928757SGary Mills static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
64*b9a86732SToomas Soome static char *boot_line;
65*b9a86732SToomas Soome static struct boot_env {
66*b9a86732SToomas Soome 	char	*be_env;	/* ends with double ascii nul */
67*b9a86732SToomas Soome 	size_t	be_size;	/* size of the environment, including nul */
68*b9a86732SToomas Soome } boot_env;
69*b9a86732SToomas Soome 
70*b9a86732SToomas Soome static int serial_ischar(void);
71*b9a86732SToomas Soome static int serial_getchar(void);
72*b9a86732SToomas Soome static void serial_putchar(int);
73*b9a86732SToomas Soome static void serial_adjust_prop(void);
74*b9a86732SToomas Soome 
75*b9a86732SToomas Soome #if !defined(_BOOT)
76*b9a86732SToomas Soome /* Set if the console or mode are expressed in the boot line */
77*b9a86732SToomas Soome static int console_set, console_mode_set;
78*b9a86732SToomas Soome #endif
79*b9a86732SToomas Soome 
80843e1988Sjohnlev #if defined(__xpv)
81843e1988Sjohnlev static int console_hypervisor_redirect = B_FALSE;
820d928757SGary Mills static int console_hypervisor_device = CONS_INVALID;
830d928757SGary Mills static int console_hypervisor_tty_num = 0;
840d928757SGary Mills 
850d928757SGary Mills /* Obtain the hypervisor console type */
860d928757SGary Mills int
870d928757SGary Mills console_hypervisor_dev_type(int *tnum)
880d928757SGary Mills {
890d928757SGary Mills 	if (tnum != NULL)
900d928757SGary Mills 		*tnum = console_hypervisor_tty_num;
910d928757SGary Mills 	return (console_hypervisor_device);
920d928757SGary Mills }
93843e1988Sjohnlev #endif /* __xpv */
94843e1988Sjohnlev 
95ae115bc7Smrj /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
96843e1988Sjohnlev void
97ae115bc7Smrj clear_screen(void)
98ae115bc7Smrj {
99ae115bc7Smrj 	/*
100ae115bc7Smrj 	 * XXX should set vga mode so we don't depend on the
101843e1988Sjohnlev 	 * state left by the boot loader.  Note that we have to
102843e1988Sjohnlev 	 * enable the cursor before clearing the screen since
103843e1988Sjohnlev 	 * the cursor position is dependant upon the cursor
104843e1988Sjohnlev 	 * skew, which is initialized by vga_cursor_display()
105ae115bc7Smrj 	 */
106843e1988Sjohnlev 	vga_cursor_display();
107ae115bc7Smrj 	vga_clear(cons_color);
108ae115bc7Smrj 	vga_setpos(0, 0);
109ae115bc7Smrj }
110ae115bc7Smrj 
111ae115bc7Smrj /* Put the character C on the screen. */
112ae115bc7Smrj static void
113ae115bc7Smrj screen_putchar(int c)
114ae115bc7Smrj {
115ae115bc7Smrj 	int row, col;
116ae115bc7Smrj 
117ae115bc7Smrj 	vga_getpos(&row, &col);
118ae115bc7Smrj 	switch (c) {
119ae115bc7Smrj 	case '\t':
120ae115bc7Smrj 		col += 8 - (col % 8);
121ae115bc7Smrj 		if (col == VGA_TEXT_COLS)
122ae115bc7Smrj 			col = 79;
123ae115bc7Smrj 		vga_setpos(row, col);
124ae115bc7Smrj 		break;
125ae115bc7Smrj 
126ae115bc7Smrj 	case '\r':
127ae115bc7Smrj 		vga_setpos(row, 0);
128ae115bc7Smrj 		break;
129ae115bc7Smrj 
130ae115bc7Smrj 	case '\b':
131ae115bc7Smrj 		if (col > 0)
132ae115bc7Smrj 			vga_setpos(row, col - 1);
133ae115bc7Smrj 		break;
134ae115bc7Smrj 
135ae115bc7Smrj 	case '\n':
136ae115bc7Smrj 		if (row < VGA_TEXT_ROWS - 1)
137ae115bc7Smrj 			vga_setpos(row + 1, col);
138ae115bc7Smrj 		else
139ae115bc7Smrj 			vga_scroll(cons_color);
140ae115bc7Smrj 		break;
141ae115bc7Smrj 
142ae115bc7Smrj 	default:
143ae115bc7Smrj 		vga_drawc(c, cons_color);
144ae115bc7Smrj 		if (col < VGA_TEXT_COLS -1)
145ae115bc7Smrj 			vga_setpos(row, col + 1);
146ae115bc7Smrj 		else if (row < VGA_TEXT_ROWS - 1)
147ae115bc7Smrj 			vga_setpos(row + 1, 0);
148ae115bc7Smrj 		else {
149ae115bc7Smrj 			vga_setpos(row, 0);
150ae115bc7Smrj 			vga_scroll(cons_color);
151ae115bc7Smrj 		}
152ae115bc7Smrj 		break;
153ae115bc7Smrj 	}
154ae115bc7Smrj }
155ae115bc7Smrj 
156ae115bc7Smrj static int port;
157ae115bc7Smrj 
158ae115bc7Smrj static void
159ae115bc7Smrj serial_init(void)
160ae115bc7Smrj {
1610d928757SGary Mills 	port = tty_addr[tty_num];
162ae115bc7Smrj 
163ae115bc7Smrj 	outb(port + ISR, 0x20);
164ae115bc7Smrj 	if (inb(port + ISR) & 0x20) {
165ae115bc7Smrj 		/*
166ae115bc7Smrj 		 * 82510 chip is present
167ae115bc7Smrj 		 */
168ae115bc7Smrj 		outb(port + DAT+7, 0x04);	/* clear status */
169ae115bc7Smrj 		outb(port + ISR, 0x40);  /* set to bank 2 */
170ae115bc7Smrj 		outb(port + MCR, 0x08);  /* IMD */
171ae115bc7Smrj 		outb(port + DAT, 0x21);  /* FMD */
172ae115bc7Smrj 		outb(port + ISR, 0x00);  /* set to bank 0 */
173ae115bc7Smrj 	} else {
174ae115bc7Smrj 		/*
175ae115bc7Smrj 		 * set the UART in FIFO mode if it has FIFO buffers.
176ae115bc7Smrj 		 * use 16550 fifo reset sequence specified in NS
177ae115bc7Smrj 		 * application note. disable fifos until chip is
178ae115bc7Smrj 		 * initialized.
179ae115bc7Smrj 		 */
180ae115bc7Smrj 		outb(port + FIFOR, 0x00);		/* clear */
181ae115bc7Smrj 		outb(port + FIFOR, FIFO_ON);		/* enable */
182ae115bc7Smrj 		outb(port + FIFOR, FIFO_ON|FIFORXFLSH);  /* reset */
183ae115bc7Smrj 		outb(port + FIFOR,
184ae115bc7Smrj 		    FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80);
185ae115bc7Smrj 		if ((inb(port + ISR) & 0xc0) != 0xc0) {
186ae115bc7Smrj 			/*
187ae115bc7Smrj 			 * no fifo buffers so disable fifos.
188ae115bc7Smrj 			 * this is true for 8250's
189ae115bc7Smrj 			 */
190ae115bc7Smrj 			outb(port + FIFOR, 0x00);
191ae115bc7Smrj 		}
192ae115bc7Smrj 	}
193ae115bc7Smrj 
194ae115bc7Smrj 	/* disable interrupts */
195ae115bc7Smrj 	outb(port + ICR, 0);
196ae115bc7Smrj 
197843e1988Sjohnlev #if !defined(_BOOT)
198843e1988Sjohnlev 	if (IN_XPV_PANIC())
199843e1988Sjohnlev 		return;
200843e1988Sjohnlev #endif
201843e1988Sjohnlev 
202ae115bc7Smrj 	/* adjust setting based on tty properties */
203ae115bc7Smrj 	serial_adjust_prop();
204ae115bc7Smrj 
205ae115bc7Smrj #if defined(_BOOT)
206ae115bc7Smrj 	/*
207ae115bc7Smrj 	 * Do a full reset to match console behavior.
208ae115bc7Smrj 	 * 0x1B + c - reset everything
209ae115bc7Smrj 	 */
210ae115bc7Smrj 	serial_putchar(0x1B);
211ae115bc7Smrj 	serial_putchar('c');
212ae115bc7Smrj #endif
213ae115bc7Smrj }
214ae115bc7Smrj 
215adb91f47Srscott /* Advance str pointer past white space */
216adb91f47Srscott #define	EAT_WHITE_SPACE(str)	{			\
217adb91f47Srscott 	while ((*str != '\0') && ISSPACE(*str))		\
218adb91f47Srscott 		str++;					\
219adb91f47Srscott }
220adb91f47Srscott 
221adb91f47Srscott /*
222adb91f47Srscott  * boot_line is set when we call here.  Search it for the argument name,
223adb91f47Srscott  * and if found, return a pointer to it.
224adb91f47Srscott  */
225adb91f47Srscott static char *
226adb91f47Srscott find_boot_line_prop(const char *name)
227adb91f47Srscott {
228adb91f47Srscott 	char *ptr;
229c6d6228cSEnrico Perla - Sun Microsystems 	char *ret = NULL;
230adb91f47Srscott 	char end_char;
231adb91f47Srscott 	size_t len;
232adb91f47Srscott 
233adb91f47Srscott 	if (boot_line == NULL)
234adb91f47Srscott 		return (NULL);
235adb91f47Srscott 
236adb91f47Srscott 	len = strlen(name);
237adb91f47Srscott 
238adb91f47Srscott 	/*
239adb91f47Srscott 	 * We have two nested loops here: the outer loop discards all options
240adb91f47Srscott 	 * except -B, and the inner loop parses the -B options looking for
241adb91f47Srscott 	 * the one we're interested in.
242adb91f47Srscott 	 */
243adb91f47Srscott 	for (ptr = boot_line; *ptr != '\0'; ptr++) {
244adb91f47Srscott 		EAT_WHITE_SPACE(ptr);
245adb91f47Srscott 
246adb91f47Srscott 		if (*ptr == '-') {
247adb91f47Srscott 			ptr++;
248adb91f47Srscott 			while ((*ptr != '\0') && (*ptr != 'B') &&
249adb91f47Srscott 			    !ISSPACE(*ptr))
250adb91f47Srscott 				ptr++;
251adb91f47Srscott 			if (*ptr == '\0')
252c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
253adb91f47Srscott 			else if (*ptr != 'B')
254adb91f47Srscott 				continue;
255adb91f47Srscott 		} else {
256adb91f47Srscott 			while ((*ptr != '\0') && !ISSPACE(*ptr))
257adb91f47Srscott 				ptr++;
258adb91f47Srscott 			if (*ptr == '\0')
259c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
260adb91f47Srscott 			continue;
261adb91f47Srscott 		}
262adb91f47Srscott 
263adb91f47Srscott 		do {
264adb91f47Srscott 			ptr++;
265adb91f47Srscott 			EAT_WHITE_SPACE(ptr);
266adb91f47Srscott 
267adb91f47Srscott 			if ((strncmp(ptr, name, len) == 0) &&
268adb91f47Srscott 			    (ptr[len] == '=')) {
269adb91f47Srscott 				ptr += len + 1;
270c6d6228cSEnrico Perla - Sun Microsystems 				if ((*ptr == '\'') || (*ptr == '"')) {
271c6d6228cSEnrico Perla - Sun Microsystems 					ret = ptr + 1;
272c6d6228cSEnrico Perla - Sun Microsystems 					end_char = *ptr;
273c6d6228cSEnrico Perla - Sun Microsystems 					ptr++;
274c6d6228cSEnrico Perla - Sun Microsystems 				} else {
275c6d6228cSEnrico Perla - Sun Microsystems 					ret = ptr;
276c6d6228cSEnrico Perla - Sun Microsystems 					end_char = ',';
277c6d6228cSEnrico Perla - Sun Microsystems 				}
278c6d6228cSEnrico Perla - Sun Microsystems 				goto consume_property;
279adb91f47Srscott 			}
280adb91f47Srscott 
281adb91f47Srscott 			/*
282adb91f47Srscott 			 * We have a property, and it's not the one we're
283adb91f47Srscott 			 * interested in.  Skip the property name.  A name
284adb91f47Srscott 			 * can end with '=', a comma, or white space.
285adb91f47Srscott 			 */
286adb91f47Srscott 			while ((*ptr != '\0') && (*ptr != '=') &&
287adb91f47Srscott 			    (*ptr != ',') && (!ISSPACE(*ptr)))
288adb91f47Srscott 				ptr++;
289adb91f47Srscott 
290adb91f47Srscott 			/*
291adb91f47Srscott 			 * We only want to go through the rest of the inner
292adb91f47Srscott 			 * loop if we have a comma.  If we have a property
293adb91f47Srscott 			 * name without a value, either continue or break.
294adb91f47Srscott 			 */
295adb91f47Srscott 			if (*ptr == '\0')
296c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
297adb91f47Srscott 			else if (*ptr == ',')
298adb91f47Srscott 				continue;
299adb91f47Srscott 			else if (ISSPACE(*ptr))
300adb91f47Srscott 				break;
301adb91f47Srscott 			ptr++;
302adb91f47Srscott 
303adb91f47Srscott 			/*
304adb91f47Srscott 			 * Is the property quoted?
305adb91f47Srscott 			 */
306adb91f47Srscott 			if ((*ptr == '\'') || (*ptr == '"')) {
307adb91f47Srscott 				end_char = *ptr;
308c6d6228cSEnrico Perla - Sun Microsystems 				ptr++;
309adb91f47Srscott 			} else {
310adb91f47Srscott 				/*
311adb91f47Srscott 				 * Not quoted, so the string ends at a comma
312adb91f47Srscott 				 * or at white space.  Deal with white space
313adb91f47Srscott 				 * later.
314adb91f47Srscott 				 */
315adb91f47Srscott 				end_char = ',';
316adb91f47Srscott 			}
317adb91f47Srscott 
318adb91f47Srscott 			/*
319adb91f47Srscott 			 * Now, we can ignore any characters until we find
320adb91f47Srscott 			 * end_char.
321adb91f47Srscott 			 */
322c6d6228cSEnrico Perla - Sun Microsystems consume_property:
323adb91f47Srscott 			for (; (*ptr != '\0') && (*ptr != end_char); ptr++) {
324adb91f47Srscott 				if ((end_char == ',') && ISSPACE(*ptr))
325adb91f47Srscott 					break;
326adb91f47Srscott 			}
327c6d6228cSEnrico Perla - Sun Microsystems 			if (*ptr && (*ptr != ',') && !ISSPACE(*ptr))
328adb91f47Srscott 				ptr++;
329adb91f47Srscott 		} while (*ptr == ',');
330adb91f47Srscott 	}
331c6d6228cSEnrico Perla - Sun Microsystems out:
332c6d6228cSEnrico Perla - Sun Microsystems 	return (ret);
333adb91f47Srscott }
334adb91f47Srscott 
335*b9a86732SToomas Soome /*
336*b9a86732SToomas Soome  * Find prop from boot env module. The data in module is list of C strings
337*b9a86732SToomas Soome  * name=value, the list is terminated by double nul.
338*b9a86732SToomas Soome  */
339*b9a86732SToomas Soome static const char *
340*b9a86732SToomas Soome find_boot_env_prop(const char *name)
341*b9a86732SToomas Soome {
342*b9a86732SToomas Soome 	char *ptr;
343*b9a86732SToomas Soome 	size_t len;
344*b9a86732SToomas Soome 	uintptr_t size;
345*b9a86732SToomas Soome 
346*b9a86732SToomas Soome 	if (boot_env.be_env == NULL)
347*b9a86732SToomas Soome 		return (NULL);
348*b9a86732SToomas Soome 
349*b9a86732SToomas Soome 	ptr = boot_env.be_env;
350*b9a86732SToomas Soome 	len = strlen(name);
351*b9a86732SToomas Soome 
352*b9a86732SToomas Soome 	/*
353*b9a86732SToomas Soome 	 * Make sure we have at least len + 2 bytes in the environment.
354*b9a86732SToomas Soome 	 * We are looking for name=value\0 constructs, and the environment
355*b9a86732SToomas Soome 	 * itself is terminated by '\0'.
356*b9a86732SToomas Soome 	 */
357*b9a86732SToomas Soome 	if (boot_env.be_size < len + 2)
358*b9a86732SToomas Soome 		return (NULL);
359*b9a86732SToomas Soome 
360*b9a86732SToomas Soome 	do {
361*b9a86732SToomas Soome 		if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) {
362*b9a86732SToomas Soome 			ptr += len + 1;
363*b9a86732SToomas Soome 			return (ptr);
364*b9a86732SToomas Soome 		}
365*b9a86732SToomas Soome 		/* find the first '\0' */
366*b9a86732SToomas Soome 		while (*ptr != '\0') {
367*b9a86732SToomas Soome 			ptr++;
368*b9a86732SToomas Soome 			size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
369*b9a86732SToomas Soome 			if (size > boot_env.be_size)
370*b9a86732SToomas Soome 				return (NULL);
371*b9a86732SToomas Soome 		}
372*b9a86732SToomas Soome 		ptr++;
373*b9a86732SToomas Soome 
374*b9a86732SToomas Soome 		/* If the remainder is shorter than name + 2, get out. */
375*b9a86732SToomas Soome 		size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
376*b9a86732SToomas Soome 		if (boot_env.be_size - size < len + 2)
377*b9a86732SToomas Soome 			return (NULL);
378*b9a86732SToomas Soome 	} while (*ptr != '\0');
379*b9a86732SToomas Soome 	return (NULL);
380*b9a86732SToomas Soome }
381*b9a86732SToomas Soome 
382*b9a86732SToomas Soome /*
383*b9a86732SToomas Soome  * Get prop value from either command line or boot environment.
384*b9a86732SToomas Soome  * We always check kernel command line first, as this will keep the
385*b9a86732SToomas Soome  * functionality and will allow user to override the values in environment.
386*b9a86732SToomas Soome  */
387*b9a86732SToomas Soome const char *
388*b9a86732SToomas Soome find_boot_prop(const char *name)
389*b9a86732SToomas Soome {
390*b9a86732SToomas Soome 	const char *value = find_boot_line_prop(name);
391*b9a86732SToomas Soome 
392*b9a86732SToomas Soome 	if (value == NULL)
393*b9a86732SToomas Soome 		value = find_boot_env_prop(name);
394*b9a86732SToomas Soome 	return (value);
395*b9a86732SToomas Soome }
396ae115bc7Smrj 
397ae115bc7Smrj #define	MATCHES(p, pat)	\
398ae115bc7Smrj 	(strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0)
399ae115bc7Smrj 
400ae115bc7Smrj #define	SKIP(p, c)				\
401ae115bc7Smrj 	while (*(p) != 0 && *p != (c))		\
402ae115bc7Smrj 		++(p);				\
403ae115bc7Smrj 	if (*(p) == (c))			\
404ae115bc7Smrj 		++(p);
405ae115bc7Smrj 
406ae115bc7Smrj /*
407ae115bc7Smrj  * find a tty mode property either from cmdline or from boot properties
408ae115bc7Smrj  */
409*b9a86732SToomas Soome static const char *
410ae115bc7Smrj get_mode_value(char *name)
411ae115bc7Smrj {
412ae115bc7Smrj 	/*
413ae115bc7Smrj 	 * when specified on boot line it looks like "name" "="....
414ae115bc7Smrj 	 */
415ae115bc7Smrj 	if (boot_line != NULL) {
416*b9a86732SToomas Soome 		return (find_boot_prop(name));
417ae115bc7Smrj 	}
418ae115bc7Smrj 
419ae115bc7Smrj #if defined(_BOOT)
420ae115bc7Smrj 	return (NULL);
421ae115bc7Smrj #else
422ae115bc7Smrj 	/*
423ae115bc7Smrj 	 * if we're running in the full kernel we check the bootenv.rc settings
424ae115bc7Smrj 	 */
425ae115bc7Smrj 	{
426ae115bc7Smrj 		static char propval[20];
427ae115bc7Smrj 
428ae115bc7Smrj 		propval[0] = 0;
429adb91f47Srscott 		if (do_bsys_getproplen(NULL, name) <= 0)
430ae115bc7Smrj 			return (NULL);
431adb91f47Srscott 		(void) do_bsys_getprop(NULL, name, propval);
432ae115bc7Smrj 		return (propval);
433ae115bc7Smrj 	}
434ae115bc7Smrj #endif
435ae115bc7Smrj }
436ae115bc7Smrj 
437ae115bc7Smrj /*
438ae115bc7Smrj  * adjust serial port based on properties
439ae115bc7Smrj  * These come either from the cmdline or from boot properties.
440ae115bc7Smrj  */
441ae115bc7Smrj static void
442ae115bc7Smrj serial_adjust_prop(void)
443ae115bc7Smrj {
444ae115bc7Smrj 	char propname[20];
445*b9a86732SToomas Soome 	const char *propval;
446*b9a86732SToomas Soome 	const char *p;
447ae115bc7Smrj 	ulong_t baud;
448ae115bc7Smrj 	uchar_t lcr = 0;
449ae115bc7Smrj 	uchar_t mcr = DTR | RTS;
450ae115bc7Smrj 
451ae115bc7Smrj 	(void) strcpy(propname, "ttyX-mode");
4520d928757SGary Mills 	propname[3] = 'a' + tty_num;
453ae115bc7Smrj 	propval = get_mode_value(propname);
454ae115bc7Smrj 	if (propval == NULL)
455ae115bc7Smrj 		propval = "9600,8,n,1,-";
456843e1988Sjohnlev #if !defined(_BOOT)
457adb91f47Srscott 	else
458adb91f47Srscott 		console_mode_set = 1;
459843e1988Sjohnlev #endif
460ae115bc7Smrj 
461ae115bc7Smrj 	/* property is of the form: "9600,8,n,1,-" */
462ae115bc7Smrj 	p = propval;
463ae115bc7Smrj 	if (MATCHES(p, "110,"))
464ae115bc7Smrj 		baud = ASY110;
465ae115bc7Smrj 	else if (MATCHES(p, "150,"))
466ae115bc7Smrj 		baud = ASY150;
467ae115bc7Smrj 	else if (MATCHES(p, "300,"))
468ae115bc7Smrj 		baud = ASY300;
469ae115bc7Smrj 	else if (MATCHES(p, "600,"))
470ae115bc7Smrj 		baud = ASY600;
471ae115bc7Smrj 	else if (MATCHES(p, "1200,"))
472ae115bc7Smrj 		baud = ASY1200;
473ae115bc7Smrj 	else if (MATCHES(p, "2400,"))
474ae115bc7Smrj 		baud = ASY2400;
475ae115bc7Smrj 	else if (MATCHES(p, "4800,"))
476ae115bc7Smrj 		baud = ASY4800;
477ae115bc7Smrj 	else if (MATCHES(p, "19200,"))
478ae115bc7Smrj 		baud = ASY19200;
479ae115bc7Smrj 	else if (MATCHES(p, "38400,"))
480ae115bc7Smrj 		baud = ASY38400;
481ae115bc7Smrj 	else if (MATCHES(p, "57600,"))
482ae115bc7Smrj 		baud = ASY57600;
483ae115bc7Smrj 	else if (MATCHES(p, "115200,"))
484ae115bc7Smrj 		baud = ASY115200;
485ae115bc7Smrj 	else {
486ae115bc7Smrj 		baud = ASY9600;
487ae115bc7Smrj 		SKIP(p, ',');
488ae115bc7Smrj 	}
489ae115bc7Smrj 	outb(port + LCR, DLAB);
490ae115bc7Smrj 	outb(port + DAT + DLL, baud & 0xff);
491ae115bc7Smrj 	outb(port + DAT + DLH, (baud >> 8) & 0xff);
492ae115bc7Smrj 
493ae115bc7Smrj 	switch (*p) {
494ae115bc7Smrj 	case '5':
495ae115bc7Smrj 		lcr |= BITS5;
496ae115bc7Smrj 		++p;
497ae115bc7Smrj 		break;
498ae115bc7Smrj 	case '6':
499ae115bc7Smrj 		lcr |= BITS6;
500ae115bc7Smrj 		++p;
501ae115bc7Smrj 		break;
502ae115bc7Smrj 	case '7':
503ae115bc7Smrj 		lcr |= BITS7;
504ae115bc7Smrj 		++p;
505ae115bc7Smrj 		break;
506ae115bc7Smrj 	case '8':
507ae115bc7Smrj 		++p;
508ae115bc7Smrj 	default:
509ae115bc7Smrj 		lcr |= BITS8;
510ae115bc7Smrj 		break;
511ae115bc7Smrj 	}
512ae115bc7Smrj 
513ae115bc7Smrj 	SKIP(p, ',');
514ae115bc7Smrj 
515ae115bc7Smrj 	switch (*p) {
516ae115bc7Smrj 	case 'n':
517ae115bc7Smrj 		lcr |= PARITY_NONE;
518ae115bc7Smrj 		++p;
519ae115bc7Smrj 		break;
520ae115bc7Smrj 	case 'o':
521ae115bc7Smrj 		lcr |= PARITY_ODD;
522ae115bc7Smrj 		++p;
523ae115bc7Smrj 		break;
524ae115bc7Smrj 	case 'e':
525ae115bc7Smrj 		++p;
526ae115bc7Smrj 	default:
527ae115bc7Smrj 		lcr |= PARITY_EVEN;
528ae115bc7Smrj 		break;
529ae115bc7Smrj 	}
530ae115bc7Smrj 
531ae115bc7Smrj 
532ae115bc7Smrj 	SKIP(p, ',');
533ae115bc7Smrj 
534ae115bc7Smrj 	switch (*p) {
535ae115bc7Smrj 	case '1':
536ae115bc7Smrj 		/* STOP1 is 0 */
537ae115bc7Smrj 		++p;
538ae115bc7Smrj 		break;
539ae115bc7Smrj 	default:
540ae115bc7Smrj 		lcr |= STOP2;
541ae115bc7Smrj 		break;
542ae115bc7Smrj 	}
543ae115bc7Smrj 	/* set parity bits */
544ae115bc7Smrj 	outb(port + LCR, lcr);
545ae115bc7Smrj 
546ae115bc7Smrj 	(void) strcpy(propname, "ttyX-rts-dtr-off");
5470d928757SGary Mills 	propname[3] = 'a' + tty_num;
548ae115bc7Smrj 	propval = get_mode_value(propname);
549ae115bc7Smrj 	if (propval == NULL)
550ae115bc7Smrj 		propval = "false";
551ae115bc7Smrj 	if (propval[0] != 'f' && propval[0] != 'F')
552ae115bc7Smrj 		mcr = 0;
553ae115bc7Smrj 	/* set modem control bits */
554ae115bc7Smrj 	outb(port + MCR, mcr | OUT2);
555ae115bc7Smrj }
556ae115bc7Smrj 
5570d928757SGary Mills /* Obtain the console type */
5580d928757SGary Mills int
5590d928757SGary Mills boot_console_type(int *tnum)
5600d928757SGary Mills {
5610d928757SGary Mills 	if (tnum != NULL)
5620d928757SGary Mills 		*tnum = tty_num;
5630d928757SGary Mills 	return (console);
5640d928757SGary Mills }
5650d928757SGary Mills 
566adb91f47Srscott /*
567adb91f47Srscott  * A structure to map console names to values.
568adb91f47Srscott  */
569adb91f47Srscott typedef struct {
570adb91f47Srscott 	char *name;
571adb91f47Srscott 	int value;
572adb91f47Srscott } console_value_t;
573adb91f47Srscott 
574adb91f47Srscott console_value_t console_devices[] = {
5750d928757SGary Mills 	{ "ttya", CONS_TTY },	/* 0 */
5760d928757SGary Mills 	{ "ttyb", CONS_TTY },	/* 1 */
5770d928757SGary Mills 	{ "ttyc", CONS_TTY },	/* 2 */
5780d928757SGary Mills 	{ "ttyd", CONS_TTY },	/* 3 */
579adb91f47Srscott 	{ "text", CONS_SCREEN_TEXT },
58067ce1dadSJan Setje-Eilers 	{ "graphics", CONS_SCREEN_GRAPHICS },
581843e1988Sjohnlev #if defined(__xpv)
582843e1988Sjohnlev 	{ "hypervisor", CONS_HYPERVISOR },
583843e1988Sjohnlev #endif
584adb91f47Srscott #if !defined(_BOOT)
585adb91f47Srscott 	{ "usb-serial", CONS_USBSER },
586adb91f47Srscott #endif
5870d928757SGary Mills 	{ NULL, CONS_INVALID }
588adb91f47Srscott };
589adb91f47Srscott 
590*b9a86732SToomas Soome static void
591*b9a86732SToomas Soome bcons_init_env(struct xboot_info *xbi)
592*b9a86732SToomas Soome {
593*b9a86732SToomas Soome 	uint32_t i;
594*b9a86732SToomas Soome 	struct boot_modules *modules;
595*b9a86732SToomas Soome 
596*b9a86732SToomas Soome 	modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
597*b9a86732SToomas Soome 	for (i = 0; i < xbi->bi_module_cnt; i++) {
598*b9a86732SToomas Soome 		if (modules[i].bm_type == BMT_ENV)
599*b9a86732SToomas Soome 			break;
600*b9a86732SToomas Soome 	}
601*b9a86732SToomas Soome 	if (i == xbi->bi_module_cnt)
602*b9a86732SToomas Soome 		return;
603*b9a86732SToomas Soome 
604*b9a86732SToomas Soome 	boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
605*b9a86732SToomas Soome 	boot_env.be_size = modules[i].bm_size;
606*b9a86732SToomas Soome }
607*b9a86732SToomas Soome 
608ae115bc7Smrj void
609*b9a86732SToomas Soome bcons_init(struct xboot_info *xbi)
610ae115bc7Smrj {
611adb91f47Srscott 	console_value_t *consolep;
612adb91f47Srscott 	size_t len, cons_len;
613*b9a86732SToomas Soome 	const char *cons_str;
6149db7147eSSherry Moore #if !defined(_BOOT)
6159db7147eSSherry Moore 	static char console_text[] = "text";
6169db7147eSSherry Moore 	extern int post_fastreboot;
6179db7147eSSherry Moore #endif
618adb91f47Srscott 
619*b9a86732SToomas Soome 	/* Set up data to fetch properties from commad line and boot env. */
620*b9a86732SToomas Soome 	boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
621*b9a86732SToomas Soome 	bcons_init_env(xbi);
622ae115bc7Smrj 	console = CONS_INVALID;
623ae115bc7Smrj 
624843e1988Sjohnlev #if defined(__xpv)
625*b9a86732SToomas Soome 	bcons_init_xen(boot_line);
626843e1988Sjohnlev #endif /* __xpv */
627843e1988Sjohnlev 
628*b9a86732SToomas Soome 	cons_str = find_boot_prop("console");
629adb91f47Srscott 	if (cons_str == NULL)
630*b9a86732SToomas Soome 		cons_str = find_boot_prop("output-device");
631adb91f47Srscott 
6329db7147eSSherry Moore #if !defined(_BOOT)
6339db7147eSSherry Moore 	if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
6349db7147eSSherry Moore 		cons_str = console_text;
6359db7147eSSherry Moore #endif
6369db7147eSSherry Moore 
637adb91f47Srscott 	/*
638adb91f47Srscott 	 * Go through the console_devices array trying to match the string
639adb91f47Srscott 	 * we were given.  The string on the command line must end with
640adb91f47Srscott 	 * a comma or white space.
641adb91f47Srscott 	 */
642adb91f47Srscott 	if (cons_str != NULL) {
6430d928757SGary Mills 		int n;
6440d928757SGary Mills 
645adb91f47Srscott 		cons_len = strlen(cons_str);
6460d928757SGary Mills 		for (n = 0; console_devices[n].name != NULL; n++) {
6470d928757SGary Mills 			consolep = &console_devices[n];
648adb91f47Srscott 			len = strlen(consolep->name);
649adb91f47Srscott 			if ((len <= cons_len) && ((cons_str[len] == '\0') ||
650adb91f47Srscott 			    (cons_str[len] == ',') || (cons_str[len] == '\'') ||
651adb91f47Srscott 			    (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
652adb91f47Srscott 			    (strncmp(cons_str, consolep->name, len) == 0)) {
653adb91f47Srscott 				console = consolep->value;
6540d928757SGary Mills 				if (console == CONS_TTY)
6550d928757SGary Mills 					tty_num = n;
656adb91f47Srscott 				break;
657adb91f47Srscott 			}
658adb91f47Srscott 		}
659adb91f47Srscott 	}
660ae115bc7Smrj 
661843e1988Sjohnlev #if defined(__xpv)
662843e1988Sjohnlev 	/*
663843e1988Sjohnlev 	 * domU's always use the hypervisor regardless of what
664843e1988Sjohnlev 	 * the console variable may be set to.
665843e1988Sjohnlev 	 */
666843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
667843e1988Sjohnlev 		console = CONS_HYPERVISOR;
668843e1988Sjohnlev 		console_hypervisor_redirect = B_TRUE;
669843e1988Sjohnlev 	}
670843e1988Sjohnlev #endif /* __xpv */
671843e1988Sjohnlev 
672ae115bc7Smrj 	/*
673ae115bc7Smrj 	 * If no console device specified, default to text.
674ae115bc7Smrj 	 * Remember what was specified for second phase.
675ae115bc7Smrj 	 */
676ae115bc7Smrj 	if (console == CONS_INVALID)
677ae115bc7Smrj 		console = CONS_SCREEN_TEXT;
678843e1988Sjohnlev #if !defined(_BOOT)
679adb91f47Srscott 	else
680adb91f47Srscott 		console_set = 1;
681843e1988Sjohnlev #endif
682843e1988Sjohnlev 
683843e1988Sjohnlev #if defined(__xpv)
684843e1988Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
685843e1988Sjohnlev 		switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) {
686843e1988Sjohnlev 			case XEN_CONSOLE_COM1:
687843e1988Sjohnlev 			case XEN_CONSOLE_COM2:
6880d928757SGary Mills 				console_hypervisor_device = CONS_TTY;
6890d928757SGary Mills 				console_hypervisor_tty_num = tty_num;
690843e1988Sjohnlev 				break;
691843e1988Sjohnlev 			case XEN_CONSOLE_VGA:
692843e1988Sjohnlev 				/*
693843e1988Sjohnlev 				 * Currently xen doesn't really support
694843e1988Sjohnlev 				 * keyboard/display console devices.
695843e1988Sjohnlev 				 * What this setting means is that
696843e1988Sjohnlev 				 * "vga=keep" has been enabled, which is
697843e1988Sjohnlev 				 * more of a xen debugging tool that a
698843e1988Sjohnlev 				 * true console mode.  Hence, we're going
699843e1988Sjohnlev 				 * to ignore this xen "console" setting.
700843e1988Sjohnlev 				 */
701843e1988Sjohnlev 				/*FALLTHROUGH*/
702843e1988Sjohnlev 			default:
703843e1988Sjohnlev 				console_hypervisor_device = CONS_INVALID;
704843e1988Sjohnlev 		}
705843e1988Sjohnlev 	}
706843e1988Sjohnlev 
707843e1988Sjohnlev 	/*
708843e1988Sjohnlev 	 * if the hypervisor is using the currently selected serial
709843e1988Sjohnlev 	 * port then default to using the hypervisor as the console
710843e1988Sjohnlev 	 * device.
711843e1988Sjohnlev 	 */
712843e1988Sjohnlev 	if (console == console_hypervisor_device) {
713843e1988Sjohnlev 		console = CONS_HYPERVISOR;
714843e1988Sjohnlev 		console_hypervisor_redirect = B_TRUE;
715843e1988Sjohnlev 	}
716843e1988Sjohnlev #endif /* __xpv */
717ae115bc7Smrj 
718ae115bc7Smrj 	switch (console) {
7190d928757SGary Mills 	case CONS_TTY:
720ae115bc7Smrj 		serial_init();
721ae115bc7Smrj 		break;
722ae115bc7Smrj 
723843e1988Sjohnlev 	case CONS_HYPERVISOR:
724843e1988Sjohnlev 		break;
725843e1988Sjohnlev 
726adb91f47Srscott #if !defined(_BOOT)
727adb91f47Srscott 	case CONS_USBSER:
728adb91f47Srscott 		/*
729adb91f47Srscott 		 * We can't do anything with the usb serial
730adb91f47Srscott 		 * until we have memory management.
731adb91f47Srscott 		 */
732adb91f47Srscott 		break;
733adb91f47Srscott #endif
73467ce1dadSJan Setje-Eilers 	case CONS_SCREEN_GRAPHICS:
73567ce1dadSJan Setje-Eilers 		kb_init();
73667ce1dadSJan Setje-Eilers 		break;
737ae115bc7Smrj 	case CONS_SCREEN_TEXT:
738ae115bc7Smrj 	default:
739ae115bc7Smrj #if defined(_BOOT)
740843e1988Sjohnlev 		clear_screen();	/* clears the grub or xen screen */
741843e1988Sjohnlev #endif /* _BOOT */
742ae115bc7Smrj 		kb_init();
743ae115bc7Smrj 		break;
744ae115bc7Smrj 	}
745ae115bc7Smrj }
746ae115bc7Smrj 
747843e1988Sjohnlev #if !defined(_BOOT)
748ae115bc7Smrj /*
749ae115bc7Smrj  * 2nd part of console initialization.
750ae115bc7Smrj  * In the kernel (ie. fakebop), this can be used only to switch to
751ae115bc7Smrj  * using a serial port instead of screen based on the contents
752ae115bc7Smrj  * of the bootenv.rc file.
753ae115bc7Smrj  */
754ae115bc7Smrj /*ARGSUSED*/
755ae115bc7Smrj void
756ae115bc7Smrj bcons_init2(char *inputdev, char *outputdev, char *consoledev)
757ae115bc7Smrj {
758ae115bc7Smrj 	int cons = CONS_INVALID;
7590d928757SGary Mills 	int ttyn;
760adb91f47Srscott 	char *devnames[] = { consoledev, outputdev, inputdev, NULL };
761adb91f47Srscott 	console_value_t *consolep;
762adb91f47Srscott 	int i;
7639db7147eSSherry Moore 	extern int post_fastreboot;
7649db7147eSSherry Moore 
7659db7147eSSherry Moore 	if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
7669db7147eSSherry Moore 		console = CONS_SCREEN_TEXT;
767ae115bc7Smrj 
768c6d6228cSEnrico Perla - Sun Microsystems 	if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) {
769adb91f47Srscott 		if (console_set) {
770adb91f47Srscott 			/*
771adb91f47Srscott 			 * If the console was set on the command line,
772adb91f47Srscott 			 * but the ttyX-mode was not, we only need to
773adb91f47Srscott 			 * check bootenv.rc for that setting.
774adb91f47Srscott 			 */
7750d928757SGary Mills 			if ((!console_mode_set) && (console == CONS_TTY))
776adb91f47Srscott 				serial_init();
777adb91f47Srscott 			return;
778ae115bc7Smrj 		}
779ae115bc7Smrj 
780adb91f47Srscott 		for (i = 0; devnames[i] != NULL; i++) {
7810d928757SGary Mills 			int n;
7820d928757SGary Mills 
7830d928757SGary Mills 			for (n = 0; console_devices[n].name != NULL; n++) {
7840d928757SGary Mills 				consolep = &console_devices[n];
785adb91f47Srscott 				if (strcmp(devnames[i], consolep->name) == 0) {
786adb91f47Srscott 					cons = consolep->value;
7870d928757SGary Mills 					if (cons == CONS_TTY)
7880d928757SGary Mills 						ttyn = n;
789ae115bc7Smrj 				}
790adb91f47Srscott 			}
791adb91f47Srscott 			if (cons != CONS_INVALID)
792adb91f47Srscott 				break;
793ae115bc7Smrj 		}
794ae115bc7Smrj 
795843e1988Sjohnlev #if defined(__xpv)
796843e1988Sjohnlev 		/*
797843e1988Sjohnlev 		 * if the hypervisor is using the currently selected console
798843e1988Sjohnlev 		 * device then default to using the hypervisor as the console
799843e1988Sjohnlev 		 * device.
800843e1988Sjohnlev 		 */
801843e1988Sjohnlev 		if (cons == console_hypervisor_device) {
802843e1988Sjohnlev 			cons = CONS_HYPERVISOR;
803843e1988Sjohnlev 			console_hypervisor_redirect = B_TRUE;
804843e1988Sjohnlev 		}
805843e1988Sjohnlev #endif /* __xpv */
806843e1988Sjohnlev 
807843e1988Sjohnlev 		if ((cons == CONS_INVALID) || (cons == console)) {
808843e1988Sjohnlev 			/*
809843e1988Sjohnlev 			 * we're sticking with whatever the current setting is
810843e1988Sjohnlev 			 */
811ae115bc7Smrj 			return;
812843e1988Sjohnlev 		}
813ae115bc7Smrj 
814ae115bc7Smrj 		console = cons;
8150d928757SGary Mills 		if (cons == CONS_TTY) {
8160d928757SGary Mills 			tty_num = ttyn;
817ae115bc7Smrj 			serial_init();
818ae115bc7Smrj 			return;
819ae115bc7Smrj 		}
820c6d6228cSEnrico Perla - Sun Microsystems 	} else {
821ae115bc7Smrj 		/*
822c6d6228cSEnrico Perla - Sun Microsystems 		 * USB serial and GRAPHICS console
823c6d6228cSEnrico Perla - Sun Microsystems 		 * we just collect data into a buffer
824ae115bc7Smrj 		 */
82548633f18SJan Setje-Eilers 		extern void *defcons_init(size_t);
82648633f18SJan Setje-Eilers 		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
827ae115bc7Smrj 	}
828ae115bc7Smrj }
829ae115bc7Smrj 
830843e1988Sjohnlev #if defined(__xpv)
831843e1988Sjohnlev boolean_t
832843e1988Sjohnlev bcons_hypervisor_redirect(void)
833843e1988Sjohnlev {
834843e1988Sjohnlev 	return (console_hypervisor_redirect);
835843e1988Sjohnlev }
836843e1988Sjohnlev 
837843e1988Sjohnlev void
838843e1988Sjohnlev bcons_device_change(int new_console)
839843e1988Sjohnlev {
840843e1988Sjohnlev 	if (new_console < CONS_MIN || new_console > CONS_MAX)
841843e1988Sjohnlev 		return;
842843e1988Sjohnlev 
843843e1988Sjohnlev 	/*
844843e1988Sjohnlev 	 * If we are asked to switch the console to the hypervisor, that
845843e1988Sjohnlev 	 * really means to switch the console to whichever device the
846843e1988Sjohnlev 	 * hypervisor is/was using.
847843e1988Sjohnlev 	 */
848843e1988Sjohnlev 	if (new_console == CONS_HYPERVISOR)
849843e1988Sjohnlev 		new_console = console_hypervisor_device;
850843e1988Sjohnlev 
851843e1988Sjohnlev 	console = new_console;
852843e1988Sjohnlev 
8530d928757SGary Mills 	if (new_console == CONS_TTY) {
8540d928757SGary Mills 		tty_num = console_hypervisor_tty_num;
855843e1988Sjohnlev 		serial_init();
856843e1988Sjohnlev 	}
8570d928757SGary Mills }
858843e1988Sjohnlev #endif /* __xpv */
859843e1988Sjohnlev 
860ae115bc7Smrj static void
86148633f18SJan Setje-Eilers defcons_putchar(int c)
862ae115bc7Smrj {
863c6d6228cSEnrico Perla - Sun Microsystems 	if (defcons_buf != NULL &&
864c6d6228cSEnrico Perla - Sun Microsystems 	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
86548633f18SJan Setje-Eilers 		*defcons_cur++ = c;
86663dd072cSJan Setje-Eilers 		*defcons_cur = 0;
86763dd072cSJan Setje-Eilers 	}
868ae115bc7Smrj }
869ae115bc7Smrj #endif	/* _BOOT */
870ae115bc7Smrj 
871ae115bc7Smrj static void
872ae115bc7Smrj serial_putchar(int c)
873ae115bc7Smrj {
874ae115bc7Smrj 	int checks = 10000;
875ae115bc7Smrj 
876ae115bc7Smrj 	while (((inb(port + LSR) & XHRE) == 0) && checks--)
877ae115bc7Smrj 		;
878ae115bc7Smrj 	outb(port + DAT, (char)c);
879ae115bc7Smrj }
880ae115bc7Smrj 
881ae115bc7Smrj static int
882ae115bc7Smrj serial_getchar(void)
883ae115bc7Smrj {
884ae115bc7Smrj 	uchar_t lsr;
885ae115bc7Smrj 
886ae115bc7Smrj 	while (serial_ischar() == 0)
887ae115bc7Smrj 		;
888ae115bc7Smrj 
889ae115bc7Smrj 	lsr = inb(port + LSR);
890ae115bc7Smrj 	if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
891ae115bc7Smrj 	    SERIAL_PARITY | SERIAL_OVERRUN)) {
892ae115bc7Smrj 		if (lsr & SERIAL_OVERRUN) {
893ae115bc7Smrj 			return (inb(port + DAT));
894ae115bc7Smrj 		} else {
895ae115bc7Smrj 			/* Toss the garbage */
896ae115bc7Smrj 			(void) inb(port + DAT);
897ae115bc7Smrj 			return (0);
898ae115bc7Smrj 		}
899ae115bc7Smrj 	}
900ae115bc7Smrj 	return (inb(port + DAT));
901ae115bc7Smrj }
902ae115bc7Smrj 
903ae115bc7Smrj static int
904ae115bc7Smrj serial_ischar(void)
905ae115bc7Smrj {
906ae115bc7Smrj 	return (inb(port + LSR) & RCA);
907ae115bc7Smrj }
908ae115bc7Smrj 
909ae115bc7Smrj static void
910ae115bc7Smrj _doputchar(int c)
911ae115bc7Smrj {
912ae115bc7Smrj 	switch (console) {
9130d928757SGary Mills 	case CONS_TTY:
914ae115bc7Smrj 		serial_putchar(c);
915ae115bc7Smrj 		return;
916ae115bc7Smrj 	case CONS_SCREEN_TEXT:
917ae115bc7Smrj 		screen_putchar(c);
918ae115bc7Smrj 		return;
91967ce1dadSJan Setje-Eilers 	case CONS_SCREEN_GRAPHICS:
920ae115bc7Smrj #if !defined(_BOOT)
921ae115bc7Smrj 	case CONS_USBSER:
92248633f18SJan Setje-Eilers 		defcons_putchar(c);
923ae115bc7Smrj #endif /* _BOOT */
92448633f18SJan Setje-Eilers 		return;
925ae115bc7Smrj 	}
926ae115bc7Smrj }
927ae115bc7Smrj 
928ae115bc7Smrj void
929ae115bc7Smrj bcons_putchar(int c)
930ae115bc7Smrj {
931ae115bc7Smrj 	static int bhcharpos = 0;
932ae115bc7Smrj 
933843e1988Sjohnlev #if defined(__xpv)
934843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
935843e1988Sjohnlev 	    console == CONS_HYPERVISOR) {
936843e1988Sjohnlev 		bcons_putchar_xen(c);
937843e1988Sjohnlev 		return;
938843e1988Sjohnlev 	}
939843e1988Sjohnlev #endif /* __xpv */
940843e1988Sjohnlev 
941ae115bc7Smrj 	if (c == '\t') {
942ae115bc7Smrj 		do {
943ae115bc7Smrj 			_doputchar(' ');
944ae115bc7Smrj 		} while (++bhcharpos % 8);
945ae115bc7Smrj 		return;
946ae115bc7Smrj 	} else  if (c == '\n' || c == '\r') {
947ae115bc7Smrj 		bhcharpos = 0;
948ae115bc7Smrj 		_doputchar('\r');
949ae115bc7Smrj 		_doputchar(c);
950ae115bc7Smrj 		return;
951ae115bc7Smrj 	} else if (c == '\b') {
952ae115bc7Smrj 		if (bhcharpos)
953ae115bc7Smrj 			bhcharpos--;
954ae115bc7Smrj 		_doputchar(c);
955ae115bc7Smrj 		return;
956ae115bc7Smrj 	}
957ae115bc7Smrj 
958ae115bc7Smrj 	bhcharpos++;
959ae115bc7Smrj 	_doputchar(c);
960ae115bc7Smrj }
961ae115bc7Smrj 
962ae115bc7Smrj /*
963ae115bc7Smrj  * kernel character input functions
964ae115bc7Smrj  */
965ae115bc7Smrj int
966ae115bc7Smrj bcons_getchar(void)
967ae115bc7Smrj {
968843e1988Sjohnlev #if defined(__xpv)
969843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
970843e1988Sjohnlev 	    console == CONS_HYPERVISOR)
971843e1988Sjohnlev 		return (bcons_getchar_xen());
972843e1988Sjohnlev #endif /* __xpv */
973843e1988Sjohnlev 
974ae115bc7Smrj 	switch (console) {
9750d928757SGary Mills 	case CONS_TTY:
976ae115bc7Smrj 		return (serial_getchar());
977ae115bc7Smrj 	default:
978ae115bc7Smrj 		return (kb_getchar());
979ae115bc7Smrj 	}
980ae115bc7Smrj }
981ae115bc7Smrj 
982ae115bc7Smrj #if !defined(_BOOT)
983ae115bc7Smrj 
984ae115bc7Smrj int
985ae115bc7Smrj bcons_ischar(void)
986ae115bc7Smrj {
987843e1988Sjohnlev 
988843e1988Sjohnlev #if defined(__xpv)
989843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
990843e1988Sjohnlev 	    console == CONS_HYPERVISOR)
991843e1988Sjohnlev 		return (bcons_ischar_xen());
992843e1988Sjohnlev #endif /* __xpv */
993843e1988Sjohnlev 
994ae115bc7Smrj 	switch (console) {
9950d928757SGary Mills 	case CONS_TTY:
996ae115bc7Smrj 		return (serial_ischar());
997ae115bc7Smrj 	default:
998ae115bc7Smrj 		return (kb_ischar());
999ae115bc7Smrj 	}
1000ae115bc7Smrj }
1001ae115bc7Smrj 
1002ae115bc7Smrj #endif /* _BOOT */
1003