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
232e6e9b6bSJohn Levon  * Copyright 2020 Joyent, Inc.
240d928757SGary Mills  *
2548633f18SJan Setje-Eilers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26ae115bc7Smrj  * Use is subject to license terms.
27ae115bc7Smrj  */
28ae115bc7Smrj 
292e6e9b6bSJohn Levon /*
302e6e9b6bSJohn Levon  * Boot console support.  Most of the file is shared between dboot, and the
312e6e9b6bSJohn Levon  * early kernel / fakebop.
322e6e9b6bSJohn Levon  */
332e6e9b6bSJohn Levon 
34ae115bc7Smrj #include <sys/types.h>
35ae115bc7Smrj #include <sys/systm.h>
36ae115bc7Smrj #include <sys/archsystm.h>
378e6d016fSToomas Soome #include <sys/framebuffer.h>
38ae115bc7Smrj #include <sys/boot_console.h>
39843e1988Sjohnlev #include <sys/panic.h>
40adb91f47Srscott #include <sys/ctype.h>
418e6d016fSToomas Soome #include <sys/ascii.h>
428e6d016fSToomas Soome #include <sys/vgareg.h>
43843e1988Sjohnlev #if defined(__xpv)
44843e1988Sjohnlev #include <sys/hypervisor.h>
45843e1988Sjohnlev #endif /* __xpv */
46ae115bc7Smrj 
478e6d016fSToomas Soome #include "boot_console_impl.h"
48ae115bc7Smrj #include "boot_serial.h"
49ae115bc7Smrj 
50ae115bc7Smrj #if defined(_BOOT)
51843e1988Sjohnlev #include <dboot/dboot_asm.h>
52adb91f47Srscott #include <dboot/dboot_xboot.h>
53843e1988Sjohnlev #else /* _BOOT */
54ae115bc7Smrj #include <sys/bootconf.h>
55843e1988Sjohnlev #if defined(__xpv)
56843e1988Sjohnlev #include <sys/evtchn_impl.h>
57843e1988Sjohnlev #endif /* __xpv */
5848633f18SJan Setje-Eilers static char *defcons_buf;
5948633f18SJan Setje-Eilers static char *defcons_cur;
60843e1988Sjohnlev #endif /* _BOOT */
61843e1988Sjohnlev 
62843e1988Sjohnlev #if defined(__xpv)
63843e1988Sjohnlev extern void bcons_init_xen(char *);
64843e1988Sjohnlev extern void bcons_putchar_xen(int);
65843e1988Sjohnlev extern int bcons_getchar_xen(void);
66843e1988Sjohnlev extern int bcons_ischar_xen(void);
67843e1988Sjohnlev #endif /* __xpv */
68ae115bc7Smrj 
698e6d016fSToomas Soome fb_info_t fb_info;
7029a77b73SToomas Soome static bcons_dev_t bcons_dev;				/* Device callbacks */
710d928757SGary Mills static int console = CONS_SCREEN_TEXT;
7260cbda0dSToomas Soome static int diag = CONS_INVALID;
730d928757SGary Mills static int tty_num = 0;
740d928757SGary Mills static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
75f289ce6eSToomas Soome static char *boot_line;
76f289ce6eSToomas Soome static struct boot_env {
77f289ce6eSToomas Soome 	char	*be_env;	/* ends with double ascii nul */
78f289ce6eSToomas Soome 	size_t	be_size;	/* size of the environment, including nul */
79f289ce6eSToomas Soome } boot_env;
80f289ce6eSToomas Soome 
8129a77b73SToomas Soome /*
8229a77b73SToomas Soome  * Simple console terminal emulator for early boot.
8329a77b73SToomas Soome  * We need this to support kmdb, all other console output is supposed
8429a77b73SToomas Soome  * to be simple text output.
8529a77b73SToomas Soome  */
8629a77b73SToomas Soome typedef enum btem_state_type {
8729a77b73SToomas Soome 	A_STATE_START,
8829a77b73SToomas Soome 	A_STATE_ESC,
8929a77b73SToomas Soome 	A_STATE_CSI,
9029a77b73SToomas Soome 	A_STATE_CSI_QMARK,
9129a77b73SToomas Soome 	A_STATE_CSI_EQUAL
9229a77b73SToomas Soome } btem_state_type_t;
9329a77b73SToomas Soome 
9429a77b73SToomas Soome #define	BTEM_MAXPARAMS	5
9529a77b73SToomas Soome typedef struct btem_state {
9629a77b73SToomas Soome 	btem_state_type_t btem_state;
9729a77b73SToomas Soome 	boolean_t btem_gotparam;
9829a77b73SToomas Soome 	int btem_curparam;
9929a77b73SToomas Soome 	int btem_paramval;
10029a77b73SToomas Soome 	int btem_params[BTEM_MAXPARAMS];
10129a77b73SToomas Soome } btem_state_t;
10229a77b73SToomas Soome 
10329a77b73SToomas Soome static btem_state_t boot_tem;
10429a77b73SToomas Soome 
105f289ce6eSToomas Soome static int serial_ischar(void);
106f289ce6eSToomas Soome static int serial_getchar(void);
107f289ce6eSToomas Soome static void serial_putchar(int);
108f289ce6eSToomas Soome static void serial_adjust_prop(void);
109f289ce6eSToomas Soome 
1102e6e9b6bSJohn Levon static void defcons_putchar(int);
1112e6e9b6bSJohn Levon 
112f289ce6eSToomas Soome #if !defined(_BOOT)
1132e6e9b6bSJohn Levon static boolean_t bootprop_set_tty_mode;
114f289ce6eSToomas Soome #endif
115f289ce6eSToomas Soome 
116843e1988Sjohnlev #if defined(__xpv)
117843e1988Sjohnlev static int console_hypervisor_redirect = B_FALSE;
1180d928757SGary Mills static int console_hypervisor_device = CONS_INVALID;
1190d928757SGary Mills static int console_hypervisor_tty_num = 0;
1200d928757SGary Mills 
1210d928757SGary Mills /* Obtain the hypervisor console type */
1220d928757SGary Mills int
1230d928757SGary Mills console_hypervisor_dev_type(int *tnum)
1240d928757SGary Mills {
1250d928757SGary Mills 	if (tnum != NULL)
1260d928757SGary Mills 		*tnum = console_hypervisor_tty_num;
1270d928757SGary Mills 	return (console_hypervisor_device);
1280d928757SGary Mills }
129843e1988Sjohnlev #endif /* __xpv */
130843e1988Sjohnlev 
131ae115bc7Smrj static int port;
132ae115bc7Smrj 
133ae115bc7Smrj static void
134ae115bc7Smrj serial_init(void)
135ae115bc7Smrj {
1360d928757SGary Mills 	port = tty_addr[tty_num];
137ae115bc7Smrj 
138ae115bc7Smrj 	outb(port + ISR, 0x20);
139ae115bc7Smrj 	if (inb(port + ISR) & 0x20) {
140ae115bc7Smrj 		/*
141ae115bc7Smrj 		 * 82510 chip is present
142ae115bc7Smrj 		 */
143ae115bc7Smrj 		outb(port + DAT+7, 0x04);	/* clear status */
144ae115bc7Smrj 		outb(port + ISR, 0x40);  /* set to bank 2 */
145ae115bc7Smrj 		outb(port + MCR, 0x08);  /* IMD */
146ae115bc7Smrj 		outb(port + DAT, 0x21);  /* FMD */
147ae115bc7Smrj 		outb(port + ISR, 0x00);  /* set to bank 0 */
148ae115bc7Smrj 	} else {
149ae115bc7Smrj 		/*
150ae115bc7Smrj 		 * set the UART in FIFO mode if it has FIFO buffers.
151ae115bc7Smrj 		 * use 16550 fifo reset sequence specified in NS
152ae115bc7Smrj 		 * application note. disable fifos until chip is
153ae115bc7Smrj 		 * initialized.
154ae115bc7Smrj 		 */
155ae115bc7Smrj 		outb(port + FIFOR, 0x00);		/* clear */
156ae115bc7Smrj 		outb(port + FIFOR, FIFO_ON);		/* enable */
157ae115bc7Smrj 		outb(port + FIFOR, FIFO_ON|FIFORXFLSH);  /* reset */
158ae115bc7Smrj 		outb(port + FIFOR,
159ae115bc7Smrj 		    FIFO_ON|FIFODMA|FIFOTXFLSH|FIFORXFLSH|0x80);
160ae115bc7Smrj 		if ((inb(port + ISR) & 0xc0) != 0xc0) {
161ae115bc7Smrj 			/*
162ae115bc7Smrj 			 * no fifo buffers so disable fifos.
163ae115bc7Smrj 			 * this is true for 8250's
164ae115bc7Smrj 			 */
165ae115bc7Smrj 			outb(port + FIFOR, 0x00);
166ae115bc7Smrj 		}
167ae115bc7Smrj 	}
168ae115bc7Smrj 
169ae115bc7Smrj 	/* disable interrupts */
170ae115bc7Smrj 	outb(port + ICR, 0);
171ae115bc7Smrj 
172843e1988Sjohnlev #if !defined(_BOOT)
173843e1988Sjohnlev 	if (IN_XPV_PANIC())
174843e1988Sjohnlev 		return;
175843e1988Sjohnlev #endif
176843e1988Sjohnlev 
177ae115bc7Smrj 	/* adjust setting based on tty properties */
178ae115bc7Smrj 	serial_adjust_prop();
179ae115bc7Smrj }
180ae115bc7Smrj 
181adb91f47Srscott /* Advance str pointer past white space */
182adb91f47Srscott #define	EAT_WHITE_SPACE(str)	{			\
183adb91f47Srscott 	while ((*str != '\0') && ISSPACE(*str))		\
184adb91f47Srscott 		str++;					\
185adb91f47Srscott }
186adb91f47Srscott 
187adb91f47Srscott /*
188adb91f47Srscott  * boot_line is set when we call here.  Search it for the argument name,
189adb91f47Srscott  * and if found, return a pointer to it.
190adb91f47Srscott  */
191adb91f47Srscott static char *
192adb91f47Srscott find_boot_line_prop(const char *name)
193adb91f47Srscott {
194adb91f47Srscott 	char *ptr;
195c6d6228cSEnrico Perla - Sun Microsystems 	char *ret = NULL;
196adb91f47Srscott 	char end_char;
197adb91f47Srscott 	size_t len;
198adb91f47Srscott 
199adb91f47Srscott 	if (boot_line == NULL)
200adb91f47Srscott 		return (NULL);
201adb91f47Srscott 
202adb91f47Srscott 	len = strlen(name);
203adb91f47Srscott 
204adb91f47Srscott 	/*
205adb91f47Srscott 	 * We have two nested loops here: the outer loop discards all options
206adb91f47Srscott 	 * except -B, and the inner loop parses the -B options looking for
207adb91f47Srscott 	 * the one we're interested in.
208adb91f47Srscott 	 */
209adb91f47Srscott 	for (ptr = boot_line; *ptr != '\0'; ptr++) {
210adb91f47Srscott 		EAT_WHITE_SPACE(ptr);
211adb91f47Srscott 
212adb91f47Srscott 		if (*ptr == '-') {
213adb91f47Srscott 			ptr++;
214adb91f47Srscott 			while ((*ptr != '\0') && (*ptr != 'B') &&
215adb91f47Srscott 			    !ISSPACE(*ptr))
216adb91f47Srscott 				ptr++;
217adb91f47Srscott 			if (*ptr == '\0')
218c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
219adb91f47Srscott 			else if (*ptr != 'B')
220adb91f47Srscott 				continue;
221adb91f47Srscott 		} else {
222adb91f47Srscott 			while ((*ptr != '\0') && !ISSPACE(*ptr))
223adb91f47Srscott 				ptr++;
224adb91f47Srscott 			if (*ptr == '\0')
225c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
226adb91f47Srscott 			continue;
227adb91f47Srscott 		}
228adb91f47Srscott 
229adb91f47Srscott 		do {
230adb91f47Srscott 			ptr++;
231adb91f47Srscott 			EAT_WHITE_SPACE(ptr);
232adb91f47Srscott 
233adb91f47Srscott 			if ((strncmp(ptr, name, len) == 0) &&
234adb91f47Srscott 			    (ptr[len] == '=')) {
235adb91f47Srscott 				ptr += len + 1;
236c6d6228cSEnrico Perla - Sun Microsystems 				if ((*ptr == '\'') || (*ptr == '"')) {
237c6d6228cSEnrico Perla - Sun Microsystems 					ret = ptr + 1;
238c6d6228cSEnrico Perla - Sun Microsystems 					end_char = *ptr;
239c6d6228cSEnrico Perla - Sun Microsystems 					ptr++;
240c6d6228cSEnrico Perla - Sun Microsystems 				} else {
241c6d6228cSEnrico Perla - Sun Microsystems 					ret = ptr;
242c6d6228cSEnrico Perla - Sun Microsystems 					end_char = ',';
243c6d6228cSEnrico Perla - Sun Microsystems 				}
244c6d6228cSEnrico Perla - Sun Microsystems 				goto consume_property;
245adb91f47Srscott 			}
246adb91f47Srscott 
247adb91f47Srscott 			/*
248adb91f47Srscott 			 * We have a property, and it's not the one we're
249adb91f47Srscott 			 * interested in.  Skip the property name.  A name
250adb91f47Srscott 			 * can end with '=', a comma, or white space.
251adb91f47Srscott 			 */
252adb91f47Srscott 			while ((*ptr != '\0') && (*ptr != '=') &&
253adb91f47Srscott 			    (*ptr != ',') && (!ISSPACE(*ptr)))
254adb91f47Srscott 				ptr++;
255adb91f47Srscott 
256adb91f47Srscott 			/*
257adb91f47Srscott 			 * We only want to go through the rest of the inner
258adb91f47Srscott 			 * loop if we have a comma.  If we have a property
259adb91f47Srscott 			 * name without a value, either continue or break.
260adb91f47Srscott 			 */
261adb91f47Srscott 			if (*ptr == '\0')
262c6d6228cSEnrico Perla - Sun Microsystems 				goto out;
263adb91f47Srscott 			else if (*ptr == ',')
264adb91f47Srscott 				continue;
265adb91f47Srscott 			else if (ISSPACE(*ptr))
266adb91f47Srscott 				break;
267adb91f47Srscott 			ptr++;
268adb91f47Srscott 
269adb91f47Srscott 			/*
270adb91f47Srscott 			 * Is the property quoted?
271adb91f47Srscott 			 */
272adb91f47Srscott 			if ((*ptr == '\'') || (*ptr == '"')) {
273adb91f47Srscott 				end_char = *ptr;
274c6d6228cSEnrico Perla - Sun Microsystems 				ptr++;
275adb91f47Srscott 			} else {
276adb91f47Srscott 				/*
277adb91f47Srscott 				 * Not quoted, so the string ends at a comma
278adb91f47Srscott 				 * or at white space.  Deal with white space
279adb91f47Srscott 				 * later.
280adb91f47Srscott 				 */
281adb91f47Srscott 				end_char = ',';
282adb91f47Srscott 			}
283adb91f47Srscott 
284adb91f47Srscott 			/*
285adb91f47Srscott 			 * Now, we can ignore any characters until we find
286adb91f47Srscott 			 * end_char.
287adb91f47Srscott 			 */
288c6d6228cSEnrico Perla - Sun Microsystems consume_property:
289adb91f47Srscott 			for (; (*ptr != '\0') && (*ptr != end_char); ptr++) {
290adb91f47Srscott 				if ((end_char == ',') && ISSPACE(*ptr))
291adb91f47Srscott 					break;
292adb91f47Srscott 			}
293c6d6228cSEnrico Perla - Sun Microsystems 			if (*ptr && (*ptr != ',') && !ISSPACE(*ptr))
294adb91f47Srscott 				ptr++;
295adb91f47Srscott 		} while (*ptr == ',');
296adb91f47Srscott 	}
297c6d6228cSEnrico Perla - Sun Microsystems out:
298c6d6228cSEnrico Perla - Sun Microsystems 	return (ret);
299adb91f47Srscott }
300adb91f47Srscott 
301f289ce6eSToomas Soome /*
302f289ce6eSToomas Soome  * Find prop from boot env module. The data in module is list of C strings
303f289ce6eSToomas Soome  * name=value, the list is terminated by double nul.
304f289ce6eSToomas Soome  */
305f289ce6eSToomas Soome static const char *
306f289ce6eSToomas Soome find_boot_env_prop(const char *name)
307f289ce6eSToomas Soome {
308f289ce6eSToomas Soome 	char *ptr;
309f289ce6eSToomas Soome 	size_t len;
310f289ce6eSToomas Soome 	uintptr_t size;
311f289ce6eSToomas Soome 
312f289ce6eSToomas Soome 	if (boot_env.be_env == NULL)
313f289ce6eSToomas Soome 		return (NULL);
314f289ce6eSToomas Soome 
315f289ce6eSToomas Soome 	ptr = boot_env.be_env;
316f289ce6eSToomas Soome 	len = strlen(name);
317f289ce6eSToomas Soome 
318f289ce6eSToomas Soome 	/*
319f289ce6eSToomas Soome 	 * Make sure we have at least len + 2 bytes in the environment.
320f289ce6eSToomas Soome 	 * We are looking for name=value\0 constructs, and the environment
321f289ce6eSToomas Soome 	 * itself is terminated by '\0'.
322f289ce6eSToomas Soome 	 */
323f289ce6eSToomas Soome 	if (boot_env.be_size < len + 2)
324f289ce6eSToomas Soome 		return (NULL);
325f289ce6eSToomas Soome 
326f289ce6eSToomas Soome 	do {
327f289ce6eSToomas Soome 		if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) {
328f289ce6eSToomas Soome 			ptr += len + 1;
329f289ce6eSToomas Soome 			return (ptr);
330f289ce6eSToomas Soome 		}
331f289ce6eSToomas Soome 		/* find the first '\0' */
332f289ce6eSToomas Soome 		while (*ptr != '\0') {
333f289ce6eSToomas Soome 			ptr++;
334f289ce6eSToomas Soome 			size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
335f289ce6eSToomas Soome 			if (size > boot_env.be_size)
336f289ce6eSToomas Soome 				return (NULL);
337f289ce6eSToomas Soome 		}
338f289ce6eSToomas Soome 		ptr++;
339f289ce6eSToomas Soome 
340f289ce6eSToomas Soome 		/* If the remainder is shorter than name + 2, get out. */
341f289ce6eSToomas Soome 		size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
342f289ce6eSToomas Soome 		if (boot_env.be_size - size < len + 2)
343f289ce6eSToomas Soome 			return (NULL);
344f289ce6eSToomas Soome 	} while (*ptr != '\0');
345f289ce6eSToomas Soome 	return (NULL);
346f289ce6eSToomas Soome }
347f289ce6eSToomas Soome 
348f289ce6eSToomas Soome /*
349f289ce6eSToomas Soome  * Get prop value from either command line or boot environment.
350f289ce6eSToomas Soome  * We always check kernel command line first, as this will keep the
351f289ce6eSToomas Soome  * functionality and will allow user to override the values in environment.
352f289ce6eSToomas Soome  */
353f289ce6eSToomas Soome const char *
354f289ce6eSToomas Soome find_boot_prop(const char *name)
355f289ce6eSToomas Soome {
356f289ce6eSToomas Soome 	const char *value = find_boot_line_prop(name);
357f289ce6eSToomas Soome 
358f289ce6eSToomas Soome 	if (value == NULL)
359f289ce6eSToomas Soome 		value = find_boot_env_prop(name);
360f289ce6eSToomas Soome 	return (value);
361f289ce6eSToomas Soome }
362ae115bc7Smrj 
363ae115bc7Smrj #define	MATCHES(p, pat)	\
364ae115bc7Smrj 	(strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0)
365ae115bc7Smrj 
366ae115bc7Smrj #define	SKIP(p, c)				\
367ae115bc7Smrj 	while (*(p) != 0 && *p != (c))		\
368ae115bc7Smrj 		++(p);				\
369ae115bc7Smrj 	if (*(p) == (c))			\
370ae115bc7Smrj 		++(p);
371ae115bc7Smrj 
372ae115bc7Smrj /*
373ae115bc7Smrj  * find a tty mode property either from cmdline or from boot properties
374ae115bc7Smrj  */
375f289ce6eSToomas Soome static const char *
376ae115bc7Smrj get_mode_value(char *name)
377ae115bc7Smrj {
378ae115bc7Smrj 	/*
379ae115bc7Smrj 	 * when specified on boot line it looks like "name" "="....
380ae115bc7Smrj 	 */
381ae115bc7Smrj 	if (boot_line != NULL) {
382f289ce6eSToomas Soome 		return (find_boot_prop(name));
383ae115bc7Smrj 	}
384ae115bc7Smrj 
385ae115bc7Smrj #if defined(_BOOT)
386ae115bc7Smrj 	return (NULL);
387ae115bc7Smrj #else
388ae115bc7Smrj 	/*
389ae115bc7Smrj 	 * if we're running in the full kernel we check the bootenv.rc settings
390ae115bc7Smrj 	 */
391ae115bc7Smrj 	{
392ae115bc7Smrj 		static char propval[20];
393ae115bc7Smrj 
394ae115bc7Smrj 		propval[0] = 0;
395adb91f47Srscott 		if (do_bsys_getproplen(NULL, name) <= 0)
396ae115bc7Smrj 			return (NULL);
397adb91f47Srscott 		(void) do_bsys_getprop(NULL, name, propval);
398ae115bc7Smrj 		return (propval);
399ae115bc7Smrj 	}
400ae115bc7Smrj #endif
401ae115bc7Smrj }
402ae115bc7Smrj 
403ae115bc7Smrj /*
404ae115bc7Smrj  * adjust serial port based on properties
405ae115bc7Smrj  * These come either from the cmdline or from boot properties.
406ae115bc7Smrj  */
407ae115bc7Smrj static void
408ae115bc7Smrj serial_adjust_prop(void)
409ae115bc7Smrj {
410ae115bc7Smrj 	char propname[20];
411f289ce6eSToomas Soome 	const char *propval;
412f289ce6eSToomas Soome 	const char *p;
413ae115bc7Smrj 	ulong_t baud;
414ae115bc7Smrj 	uchar_t lcr = 0;
415ae115bc7Smrj 	uchar_t mcr = DTR | RTS;
416ae115bc7Smrj 
417ae115bc7Smrj 	(void) strcpy(propname, "ttyX-mode");
4180d928757SGary Mills 	propname[3] = 'a' + tty_num;
419ae115bc7Smrj 	propval = get_mode_value(propname);
420843e1988Sjohnlev #if !defined(_BOOT)
4212e6e9b6bSJohn Levon 	if (propval != NULL)
4222e6e9b6bSJohn Levon 		bootprop_set_tty_mode = B_TRUE;
423843e1988Sjohnlev #endif
4242e6e9b6bSJohn Levon 	if (propval == NULL)
4252e6e9b6bSJohn Levon 		propval = "9600,8,n,1,-";
426ae115bc7Smrj 
427ae115bc7Smrj 	/* property is of the form: "9600,8,n,1,-" */
428ae115bc7Smrj 	p = propval;
429ae115bc7Smrj 	if (MATCHES(p, "110,"))
430ae115bc7Smrj 		baud = ASY110;
431ae115bc7Smrj 	else if (MATCHES(p, "150,"))
432ae115bc7Smrj 		baud = ASY150;
433ae115bc7Smrj 	else if (MATCHES(p, "300,"))
434ae115bc7Smrj 		baud = ASY300;
435ae115bc7Smrj 	else if (MATCHES(p, "600,"))
436ae115bc7Smrj 		baud = ASY600;
437ae115bc7Smrj 	else if (MATCHES(p, "1200,"))
438ae115bc7Smrj 		baud = ASY1200;
439ae115bc7Smrj 	else if (MATCHES(p, "2400,"))
440ae115bc7Smrj 		baud = ASY2400;
441ae115bc7Smrj 	else if (MATCHES(p, "4800,"))
442ae115bc7Smrj 		baud = ASY4800;
443ae115bc7Smrj 	else if (MATCHES(p, "19200,"))
444ae115bc7Smrj 		baud = ASY19200;
445ae115bc7Smrj 	else if (MATCHES(p, "38400,"))
446ae115bc7Smrj 		baud = ASY38400;
447ae115bc7Smrj 	else if (MATCHES(p, "57600,"))
448ae115bc7Smrj 		baud = ASY57600;
449ae115bc7Smrj 	else if (MATCHES(p, "115200,"))
450ae115bc7Smrj 		baud = ASY115200;
451ae115bc7Smrj 	else {
452ae115bc7Smrj 		baud = ASY9600;
453ae115bc7Smrj 		SKIP(p, ',');
454ae115bc7Smrj 	}
455ae115bc7Smrj 	outb(port + LCR, DLAB);
456ae115bc7Smrj 	outb(port + DAT + DLL, baud & 0xff);
457ae115bc7Smrj 	outb(port + DAT + DLH, (baud >> 8) & 0xff);
458ae115bc7Smrj 
459ae115bc7Smrj 	switch (*p) {
460ae115bc7Smrj 	case '5':
461ae115bc7Smrj 		lcr |= BITS5;
462ae115bc7Smrj 		++p;
463ae115bc7Smrj 		break;
464ae115bc7Smrj 	case '6':
465ae115bc7Smrj 		lcr |= BITS6;
466ae115bc7Smrj 		++p;
467ae115bc7Smrj 		break;
468ae115bc7Smrj 	case '7':
469ae115bc7Smrj 		lcr |= BITS7;
470ae115bc7Smrj 		++p;
471ae115bc7Smrj 		break;
472ae115bc7Smrj 	case '8':
473ae115bc7Smrj 		++p;
474df23f1c1SToomas Soome 		/* FALLTHROUGH */
475ae115bc7Smrj 	default:
476ae115bc7Smrj 		lcr |= BITS8;
477ae115bc7Smrj 		break;
478ae115bc7Smrj 	}
479ae115bc7Smrj 
480ae115bc7Smrj 	SKIP(p, ',');
481ae115bc7Smrj 
482ae115bc7Smrj 	switch (*p) {
483ae115bc7Smrj 	case 'n':
484ae115bc7Smrj 		lcr |= PARITY_NONE;
485ae115bc7Smrj 		++p;
486ae115bc7Smrj 		break;
487ae115bc7Smrj 	case 'o':
488ae115bc7Smrj 		lcr |= PARITY_ODD;
489ae115bc7Smrj 		++p;
490ae115bc7Smrj 		break;
491ae115bc7Smrj 	case 'e':
492ae115bc7Smrj 		++p;
493df23f1c1SToomas Soome 		/* FALLTHROUGH */
494ae115bc7Smrj 	default:
495ae115bc7Smrj 		lcr |= PARITY_EVEN;
496ae115bc7Smrj 		break;
497ae115bc7Smrj 	}
498ae115bc7Smrj 
499ae115bc7Smrj 
500ae115bc7Smrj 	SKIP(p, ',');
501ae115bc7Smrj 
502ae115bc7Smrj 	switch (*p) {
503ae115bc7Smrj 	case '1':
504ae115bc7Smrj 		/* STOP1 is 0 */
505ae115bc7Smrj 		++p;
506ae115bc7Smrj 		break;
507ae115bc7Smrj 	default:
508ae115bc7Smrj 		lcr |= STOP2;
509ae115bc7Smrj 		break;
510ae115bc7Smrj 	}
511ae115bc7Smrj 	/* set parity bits */
512ae115bc7Smrj 	outb(port + LCR, lcr);
513ae115bc7Smrj 
514ae115bc7Smrj 	(void) strcpy(propname, "ttyX-rts-dtr-off");
5150d928757SGary Mills 	propname[3] = 'a' + tty_num;
516ae115bc7Smrj 	propval = get_mode_value(propname);
517ae115bc7Smrj 	if (propval == NULL)
518ae115bc7Smrj 		propval = "false";
519ae115bc7Smrj 	if (propval[0] != 'f' && propval[0] != 'F')
520ae115bc7Smrj 		mcr = 0;
521ae115bc7Smrj 	/* set modem control bits */
522ae115bc7Smrj 	outb(port + MCR, mcr | OUT2);
523ae115bc7Smrj }
524ae115bc7Smrj 
5250d928757SGary Mills /* Obtain the console type */
5260d928757SGary Mills int
5270d928757SGary Mills boot_console_type(int *tnum)
5280d928757SGary Mills {
5290d928757SGary Mills 	if (tnum != NULL)
5300d928757SGary Mills 		*tnum = tty_num;
5310d928757SGary Mills 	return (console);
5320d928757SGary Mills }
5330d928757SGary Mills 
534adb91f47Srscott /*
535adb91f47Srscott  * A structure to map console names to values.
536adb91f47Srscott  */
537adb91f47Srscott typedef struct {
538adb91f47Srscott 	char *name;
539adb91f47Srscott 	int value;
540adb91f47Srscott } console_value_t;
541adb91f47Srscott 
542adb91f47Srscott console_value_t console_devices[] = {
5430d928757SGary Mills 	{ "ttya", CONS_TTY },	/* 0 */
5440d928757SGary Mills 	{ "ttyb", CONS_TTY },	/* 1 */
5450d928757SGary Mills 	{ "ttyc", CONS_TTY },	/* 2 */
5460d928757SGary Mills 	{ "ttyd", CONS_TTY },	/* 3 */
547adb91f47Srscott 	{ "text", CONS_SCREEN_TEXT },
54867ce1dadSJan Setje-Eilers 	{ "graphics", CONS_SCREEN_GRAPHICS },
549843e1988Sjohnlev #if defined(__xpv)
550843e1988Sjohnlev 	{ "hypervisor", CONS_HYPERVISOR },
551843e1988Sjohnlev #endif
552adb91f47Srscott #if !defined(_BOOT)
553adb91f47Srscott 	{ "usb-serial", CONS_USBSER },
554adb91f47Srscott #endif
5550d928757SGary Mills 	{ NULL, CONS_INVALID }
556adb91f47Srscott };
557adb91f47Srscott 
558f289ce6eSToomas Soome static void
559f289ce6eSToomas Soome bcons_init_env(struct xboot_info *xbi)
560f289ce6eSToomas Soome {
561f289ce6eSToomas Soome 	uint32_t i;
562f289ce6eSToomas Soome 	struct boot_modules *modules;
563f289ce6eSToomas Soome 
564f289ce6eSToomas Soome 	modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
565f289ce6eSToomas Soome 	for (i = 0; i < xbi->bi_module_cnt; i++) {
566f289ce6eSToomas Soome 		if (modules[i].bm_type == BMT_ENV)
567f289ce6eSToomas Soome 			break;
568f289ce6eSToomas Soome 	}
569f289ce6eSToomas Soome 	if (i == xbi->bi_module_cnt)
570f289ce6eSToomas Soome 		return;
571f289ce6eSToomas Soome 
572f289ce6eSToomas Soome 	boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
573f289ce6eSToomas Soome 	boot_env.be_size = modules[i].bm_size;
574f289ce6eSToomas Soome }
575f289ce6eSToomas Soome 
5768e6d016fSToomas Soome int
5778e6d016fSToomas Soome boot_fb(struct xboot_info *xbi, int console)
5788e6d016fSToomas Soome {
57929a77b73SToomas Soome 	if (xbi_fb_init(xbi, &bcons_dev) == B_FALSE)
5808e6d016fSToomas Soome 		return (console);
5818e6d016fSToomas Soome 
5828e6d016fSToomas Soome 	/* FB address is not set, fall back to serial terminal. */
58329a77b73SToomas Soome 	if (fb_info.paddr == 0)
5848e6d016fSToomas Soome 		return (CONS_TTY);
5858e6d016fSToomas Soome 
58629a77b73SToomas Soome 	fb_info.terminal.x = VGA_TEXT_COLS;
58729a77b73SToomas Soome 	fb_info.terminal.y = VGA_TEXT_ROWS;
5888e6d016fSToomas Soome 	boot_fb_init(CONS_FRAMEBUFFER);
5898e6d016fSToomas Soome 
5908e6d016fSToomas Soome 	if (console == CONS_SCREEN_TEXT)
5918e6d016fSToomas Soome 		return (CONS_FRAMEBUFFER);
5928e6d016fSToomas Soome 	return (console);
5938e6d016fSToomas Soome }
5948e6d016fSToomas Soome 
5958e6d016fSToomas Soome /*
5968e6d016fSToomas Soome  * TODO.
5978e6d016fSToomas Soome  * quick and dirty local atoi. Perhaps should build with strtol, but
5988e6d016fSToomas Soome  * dboot & early boot mix does overcomplicate things much.
5998e6d016fSToomas Soome  * Stolen from libc anyhow.
6008e6d016fSToomas Soome  */
6018e6d016fSToomas Soome static int
6028e6d016fSToomas Soome atoi(const char *p)
6038e6d016fSToomas Soome {
6048e6d016fSToomas Soome 	int n, c, neg = 0;
6058e6d016fSToomas Soome 	unsigned char *up = (unsigned char *)p;
6068e6d016fSToomas Soome 
6078e6d016fSToomas Soome 	if (!isdigit(c = *up)) {
6088e6d016fSToomas Soome 		while (isspace(c))
6098e6d016fSToomas Soome 			c = *++up;
6108e6d016fSToomas Soome 		switch (c) {
6118e6d016fSToomas Soome 		case '-':
6128e6d016fSToomas Soome 			neg++;
6138e6d016fSToomas Soome 			/* FALLTHROUGH */
6148e6d016fSToomas Soome 		case '+':
6158e6d016fSToomas Soome 			c = *++up;
6168e6d016fSToomas Soome 		}
6178e6d016fSToomas Soome 		if (!isdigit(c))
6188e6d016fSToomas Soome 			return (0);
6198e6d016fSToomas Soome 	}
6208e6d016fSToomas Soome 	for (n = '0' - c; isdigit(c = *++up); ) {
6218e6d016fSToomas Soome 		n *= 10; /* two steps to avoid unnecessary overflow */
6228e6d016fSToomas Soome 		n += '0' - c; /* accum neg to avoid surprises at MAX */
6238e6d016fSToomas Soome 	}
6248e6d016fSToomas Soome 	return (neg ? n : -n);
6258e6d016fSToomas Soome }
6268e6d016fSToomas Soome 
6278e6d016fSToomas Soome static void
6288e6d016fSToomas Soome bcons_init_fb(void)
6298e6d016fSToomas Soome {
6308e6d016fSToomas Soome 	const char *propval;
6318e6d016fSToomas Soome 	int intval;
6328e6d016fSToomas Soome 
6338e6d016fSToomas Soome 	/* initialize with explicit default values */
6348e6d016fSToomas Soome 	fb_info.fg_color = CONS_COLOR;
6358e6d016fSToomas Soome 	fb_info.bg_color = 0;
6368e6d016fSToomas Soome 	fb_info.inverse = B_FALSE;
6378e6d016fSToomas Soome 	fb_info.inverse_screen = B_FALSE;
6388e6d016fSToomas Soome 
639a4e6b9b6SToomas Soome 	/* color values are 0 - 255 */
6408e6d016fSToomas Soome 	propval = find_boot_prop("tem.fg_color");
6418e6d016fSToomas Soome 	if (propval != NULL) {
6428e6d016fSToomas Soome 		intval = atoi(propval);
643a4e6b9b6SToomas Soome 		if (intval >= 0 && intval <= 255)
6448e6d016fSToomas Soome 			fb_info.fg_color = intval;
6458e6d016fSToomas Soome 	}
6468e6d016fSToomas Soome 
647a4e6b9b6SToomas Soome 	/* color values are 0 - 255 */
6488e6d016fSToomas Soome 	propval = find_boot_prop("tem.bg_color");
6498e6d016fSToomas Soome 	if (propval != NULL && ISDIGIT(*propval)) {
6508e6d016fSToomas Soome 		intval = atoi(propval);
651a4e6b9b6SToomas Soome 		if (intval >= 0 && intval <= 255)
6528e6d016fSToomas Soome 			fb_info.bg_color = intval;
6538e6d016fSToomas Soome 	}
6548e6d016fSToomas Soome 
6558e6d016fSToomas Soome 	/* get inverses. allow 0, 1, true, false */
6568e6d016fSToomas Soome 	propval = find_boot_prop("tem.inverse");
6578e6d016fSToomas Soome 	if (propval != NULL) {
6588e6d016fSToomas Soome 		if (*propval == '1' || MATCHES(propval, "true"))
6598e6d016fSToomas Soome 			fb_info.inverse = B_TRUE;
6608e6d016fSToomas Soome 	}
6618e6d016fSToomas Soome 
6628e6d016fSToomas Soome 	propval = find_boot_prop("tem.inverse-screen");
6638e6d016fSToomas Soome 	if (propval != NULL) {
6648e6d016fSToomas Soome 		if (*propval == '1' || MATCHES(propval, "true"))
6658e6d016fSToomas Soome 			fb_info.inverse_screen = B_TRUE;
6668e6d016fSToomas Soome 	}
6678e6d016fSToomas Soome 
668cbc8e155SToomas Soome #if defined(_BOOT)
6698e6d016fSToomas Soome 	/*
6708e6d016fSToomas Soome 	 * Load cursor position from bootloader only in dboot,
6718e6d016fSToomas Soome 	 * dboot will pass cursor position to kernel via xboot info.
6728e6d016fSToomas Soome 	 */
6738e6d016fSToomas Soome 	propval = find_boot_prop("tem.cursor.row");
6748e6d016fSToomas Soome 	if (propval != NULL) {
6758e6d016fSToomas Soome 		intval = atoi(propval);
6768e6d016fSToomas Soome 		if (intval >= 0 && intval <= 0xFFFF)
6778e6d016fSToomas Soome 			fb_info.cursor.pos.y = intval;
6788e6d016fSToomas Soome 	}
6798e6d016fSToomas Soome 
6808e6d016fSToomas Soome 	propval = find_boot_prop("tem.cursor.col");
6818e6d016fSToomas Soome 	if (propval != NULL) {
6828e6d016fSToomas Soome 		intval = atoi(propval);
6838e6d016fSToomas Soome 		if (intval >= 0 && intval <= 0xFFFF)
6848e6d016fSToomas Soome 			fb_info.cursor.pos.x = intval;
6858e6d016fSToomas Soome 	}
6868e6d016fSToomas Soome #endif
6878e6d016fSToomas Soome }
6888e6d016fSToomas Soome 
68960cbda0dSToomas Soome /*
6902e6e9b6bSJohn Levon  * Go through the known console device names trying to match the string we were
6912e6e9b6bSJohn Levon  * given.  The string on the command line must end with a comma or white space.
69260cbda0dSToomas Soome  *
6932e6e9b6bSJohn Levon  * For convenience, we provide the caller with an integer index for the CONS_TTY
6942e6e9b6bSJohn Levon  * case.
69560cbda0dSToomas Soome  */
69660cbda0dSToomas Soome static int
6972e6e9b6bSJohn Levon lookup_console_device(const char *cons_str, int *indexp)
69860cbda0dSToomas Soome {
69960cbda0dSToomas Soome 	int n, cons;
70060cbda0dSToomas Soome 	size_t len, cons_len;
70160cbda0dSToomas Soome 	console_value_t *consolep;
70260cbda0dSToomas Soome 
70360cbda0dSToomas Soome 	cons = CONS_INVALID;
70460cbda0dSToomas Soome 	if (cons_str != NULL) {
70560cbda0dSToomas Soome 
70660cbda0dSToomas Soome 		cons_len = strlen(cons_str);
70760cbda0dSToomas Soome 		for (n = 0; console_devices[n].name != NULL; n++) {
70860cbda0dSToomas Soome 			consolep = &console_devices[n];
70960cbda0dSToomas Soome 			len = strlen(consolep->name);
71060cbda0dSToomas Soome 			if ((len <= cons_len) && ((cons_str[len] == '\0') ||
71160cbda0dSToomas Soome 			    (cons_str[len] == ',') || (cons_str[len] == '\'') ||
71260cbda0dSToomas Soome 			    (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
71360cbda0dSToomas Soome 			    (strncmp(cons_str, consolep->name, len) == 0)) {
71460cbda0dSToomas Soome 				cons = consolep->value;
71560cbda0dSToomas Soome 				if (cons == CONS_TTY)
7162e6e9b6bSJohn Levon 					*indexp = n;
71760cbda0dSToomas Soome 				break;
71860cbda0dSToomas Soome 			}
71960cbda0dSToomas Soome 		}
72060cbda0dSToomas Soome 	}
72160cbda0dSToomas Soome 	return (cons);
72260cbda0dSToomas Soome }
72360cbda0dSToomas Soome 
724ae115bc7Smrj void
725f289ce6eSToomas Soome bcons_init(struct xboot_info *xbi)
726ae115bc7Smrj {
727f289ce6eSToomas Soome 	const char *cons_str;
7289db7147eSSherry Moore #if !defined(_BOOT)
7299db7147eSSherry Moore 	static char console_text[] = "text";
7309db7147eSSherry Moore 	extern int post_fastreboot;
7319db7147eSSherry Moore #endif
732adb91f47Srscott 
733805e8fd0SToomas Soome 	if (xbi == NULL) {
734805e8fd0SToomas Soome 		/* This is very early dboot console, set up ttya. */
735805e8fd0SToomas Soome 		console = CONS_TTY;
736805e8fd0SToomas Soome 		serial_init();
737805e8fd0SToomas Soome 		return;
738805e8fd0SToomas Soome 	}
739805e8fd0SToomas Soome 
740f289ce6eSToomas Soome 	/* Set up data to fetch properties from commad line and boot env. */
741f289ce6eSToomas Soome 	boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
742f289ce6eSToomas Soome 	bcons_init_env(xbi);
743ae115bc7Smrj 	console = CONS_INVALID;
744ae115bc7Smrj 
7458e6d016fSToomas Soome 	/* set up initial fb_info */
7468e6d016fSToomas Soome 	bcons_init_fb();
7478e6d016fSToomas Soome 
748843e1988Sjohnlev #if defined(__xpv)
749f289ce6eSToomas Soome 	bcons_init_xen(boot_line);
750843e1988Sjohnlev #endif /* __xpv */
751843e1988Sjohnlev 
75260cbda0dSToomas Soome 	/*
75360cbda0dSToomas Soome 	 * First check for diag-device.
75460cbda0dSToomas Soome 	 */
75560cbda0dSToomas Soome 	cons_str = find_boot_prop("diag-device");
75660cbda0dSToomas Soome 	if (cons_str != NULL)
7572e6e9b6bSJohn Levon 		diag = lookup_console_device(cons_str, &tty_num);
75860cbda0dSToomas Soome 
759f289ce6eSToomas Soome 	cons_str = find_boot_prop("console");
760adb91f47Srscott 	if (cons_str == NULL)
761f289ce6eSToomas Soome 		cons_str = find_boot_prop("output-device");
762adb91f47Srscott 
7639db7147eSSherry Moore #if !defined(_BOOT)
7649db7147eSSherry Moore 	if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
7659db7147eSSherry Moore 		cons_str = console_text;
7669db7147eSSherry Moore #endif
7679db7147eSSherry Moore 
76860cbda0dSToomas Soome 	if (cons_str != NULL)
7692e6e9b6bSJohn Levon 		console = lookup_console_device(cons_str, &tty_num);
770ae115bc7Smrj 
771843e1988Sjohnlev #if defined(__xpv)
772843e1988Sjohnlev 	/*
773843e1988Sjohnlev 	 * domU's always use the hypervisor regardless of what
774843e1988Sjohnlev 	 * the console variable may be set to.
775843e1988Sjohnlev 	 */
776843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
777843e1988Sjohnlev 		console = CONS_HYPERVISOR;
778843e1988Sjohnlev 		console_hypervisor_redirect = B_TRUE;
779843e1988Sjohnlev 	}
780843e1988Sjohnlev #endif /* __xpv */
781843e1988Sjohnlev 
782ae115bc7Smrj 	if (console == CONS_INVALID)
783ae115bc7Smrj 		console = CONS_SCREEN_TEXT;
784843e1988Sjohnlev 
785843e1988Sjohnlev #if defined(__xpv)
786843e1988Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
787843e1988Sjohnlev 		switch (HYPERVISOR_console_io(CONSOLEIO_get_device, 0, NULL)) {
788843e1988Sjohnlev 			case XEN_CONSOLE_COM1:
789843e1988Sjohnlev 			case XEN_CONSOLE_COM2:
7900d928757SGary Mills 				console_hypervisor_device = CONS_TTY;
7910d928757SGary Mills 				console_hypervisor_tty_num = tty_num;
792843e1988Sjohnlev 				break;
793843e1988Sjohnlev 			case XEN_CONSOLE_VGA:
794843e1988Sjohnlev 				/*
795843e1988Sjohnlev 				 * Currently xen doesn't really support
796843e1988Sjohnlev 				 * keyboard/display console devices.
797843e1988Sjohnlev 				 * What this setting means is that
798843e1988Sjohnlev 				 * "vga=keep" has been enabled, which is
799843e1988Sjohnlev 				 * more of a xen debugging tool that a
800843e1988Sjohnlev 				 * true console mode.  Hence, we're going
801843e1988Sjohnlev 				 * to ignore this xen "console" setting.
802843e1988Sjohnlev 				 */
803843e1988Sjohnlev 				/*FALLTHROUGH*/
804843e1988Sjohnlev 			default:
805843e1988Sjohnlev 				console_hypervisor_device = CONS_INVALID;
806843e1988Sjohnlev 		}
807843e1988Sjohnlev 	}
808843e1988Sjohnlev 
809843e1988Sjohnlev 	/*
810843e1988Sjohnlev 	 * if the hypervisor is using the currently selected serial
811843e1988Sjohnlev 	 * port then default to using the hypervisor as the console
812843e1988Sjohnlev 	 * device.
813843e1988Sjohnlev 	 */
814843e1988Sjohnlev 	if (console == console_hypervisor_device) {
815843e1988Sjohnlev 		console = CONS_HYPERVISOR;
816843e1988Sjohnlev 		console_hypervisor_redirect = B_TRUE;
817843e1988Sjohnlev 	}
818843e1988Sjohnlev #endif /* __xpv */
819ae115bc7Smrj 
8208e6d016fSToomas Soome 	/* make sure the FB is set up if present */
8218e6d016fSToomas Soome 	console = boot_fb(xbi, console);
822ae115bc7Smrj 	switch (console) {
8230d928757SGary Mills 	case CONS_TTY:
824ae115bc7Smrj 		serial_init();
825ae115bc7Smrj 		break;
826ae115bc7Smrj 
827843e1988Sjohnlev 	case CONS_HYPERVISOR:
828843e1988Sjohnlev 		break;
829843e1988Sjohnlev 
830adb91f47Srscott #if !defined(_BOOT)
831adb91f47Srscott 	case CONS_USBSER:
832adb91f47Srscott 		/*
833adb91f47Srscott 		 * We can't do anything with the usb serial
834adb91f47Srscott 		 * until we have memory management.
835adb91f47Srscott 		 */
836adb91f47Srscott 		break;
837adb91f47Srscott #endif
83867ce1dadSJan Setje-Eilers 	case CONS_SCREEN_GRAPHICS:
83967ce1dadSJan Setje-Eilers 		kb_init();
84067ce1dadSJan Setje-Eilers 		break;
841ae115bc7Smrj 	case CONS_SCREEN_TEXT:
84229a77b73SToomas Soome 		boot_vga_init(&bcons_dev);
8438e6d016fSToomas Soome 		/* Fall through */
844ae115bc7Smrj 	default:
845ae115bc7Smrj 		kb_init();
846ae115bc7Smrj 		break;
847ae115bc7Smrj 	}
84860cbda0dSToomas Soome 
84960cbda0dSToomas Soome 	/*
85060cbda0dSToomas Soome 	 * Initialize diag device unless already done.
85160cbda0dSToomas Soome 	 */
85260cbda0dSToomas Soome 	switch (diag) {
85360cbda0dSToomas Soome 	case CONS_TTY:
85460cbda0dSToomas Soome 		if (console != CONS_TTY)
85560cbda0dSToomas Soome 			serial_init();
85660cbda0dSToomas Soome 		break;
85760cbda0dSToomas Soome 	case CONS_SCREEN_GRAPHICS:
85860cbda0dSToomas Soome 	case CONS_SCREEN_TEXT:
85960cbda0dSToomas Soome 		if (console != CONS_SCREEN_GRAPHICS &&
86060cbda0dSToomas Soome 		    console != CONS_SCREEN_TEXT)
86160cbda0dSToomas Soome 			kb_init();
86260cbda0dSToomas Soome 		break;
86360cbda0dSToomas Soome 	default:
86460cbda0dSToomas Soome 		break;
86560cbda0dSToomas Soome 	}
866ae115bc7Smrj }
867ae115bc7Smrj 
868ae115bc7Smrj static void
869ae115bc7Smrj serial_putchar(int c)
870ae115bc7Smrj {
871ae115bc7Smrj 	int checks = 10000;
872ae115bc7Smrj 
873ae115bc7Smrj 	while (((inb(port + LSR) & XHRE) == 0) && checks--)
874ae115bc7Smrj 		;
875ae115bc7Smrj 	outb(port + DAT, (char)c);
876ae115bc7Smrj }
877ae115bc7Smrj 
878ae115bc7Smrj static int
879ae115bc7Smrj serial_getchar(void)
880ae115bc7Smrj {
881ae115bc7Smrj 	uchar_t lsr;
882ae115bc7Smrj 
883ae115bc7Smrj 	while (serial_ischar() == 0)
884ae115bc7Smrj 		;
885ae115bc7Smrj 
886ae115bc7Smrj 	lsr = inb(port + LSR);
887ae115bc7Smrj 	if (lsr & (SERIAL_BREAK | SERIAL_FRAME |
888ae115bc7Smrj 	    SERIAL_PARITY | SERIAL_OVERRUN)) {
889ae115bc7Smrj 		if (lsr & SERIAL_OVERRUN) {
890ae115bc7Smrj 			return (inb(port + DAT));
891ae115bc7Smrj 		} else {
892ae115bc7Smrj 			/* Toss the garbage */
893ae115bc7Smrj 			(void) inb(port + DAT);
894ae115bc7Smrj 			return (0);
895ae115bc7Smrj 		}
896ae115bc7Smrj 	}
897ae115bc7Smrj 	return (inb(port + DAT));
898ae115bc7Smrj }
899ae115bc7Smrj 
900ae115bc7Smrj static int
901ae115bc7Smrj serial_ischar(void)
902ae115bc7Smrj {
903ae115bc7Smrj 	return (inb(port + LSR) & RCA);
904ae115bc7Smrj }
905ae115bc7Smrj 
90629a77b73SToomas Soome static void
90729a77b73SToomas Soome btem_control(btem_state_t *btem, int c)
90829a77b73SToomas Soome {
90929a77b73SToomas Soome 	int y, rows, cols;
91029a77b73SToomas Soome 
91129a77b73SToomas Soome 	rows = fb_info.cursor.pos.y;
91229a77b73SToomas Soome 	cols = fb_info.cursor.pos.x;
91329a77b73SToomas Soome 
91429a77b73SToomas Soome 	btem->btem_state = A_STATE_START;
91529a77b73SToomas Soome 	switch (c) {
91629a77b73SToomas Soome 	case A_BS:
91729a77b73SToomas Soome 		bcons_dev.bd_setpos(rows, cols - 1);
91829a77b73SToomas Soome 		break;
91929a77b73SToomas Soome 
92029a77b73SToomas Soome 	case A_HT:
92129a77b73SToomas Soome 		cols += 8 - (cols % 8);
92229a77b73SToomas Soome 		if (cols >= fb_info.terminal.x)
92329a77b73SToomas Soome 			cols = fb_info.terminal.x - 1;
92429a77b73SToomas Soome 		bcons_dev.bd_setpos(rows, cols);
92529a77b73SToomas Soome 		break;
92629a77b73SToomas Soome 
92729a77b73SToomas Soome 	case A_CR:
92829a77b73SToomas Soome 		bcons_dev.bd_setpos(rows, 0);
92929a77b73SToomas Soome 		break;
93029a77b73SToomas Soome 
93129a77b73SToomas Soome 	case A_FF:
93229a77b73SToomas Soome 		for (y = 0; y < fb_info.terminal.y; y++) {
93329a77b73SToomas Soome 			bcons_dev.bd_setpos(y, 0);
93429a77b73SToomas Soome 			bcons_dev.bd_eraseline();
93529a77b73SToomas Soome 		}
93629a77b73SToomas Soome 		bcons_dev.bd_setpos(0, 0);
93729a77b73SToomas Soome 		break;
93829a77b73SToomas Soome 
93929a77b73SToomas Soome 	case A_ESC:
94029a77b73SToomas Soome 		btem->btem_state = A_STATE_ESC;
94129a77b73SToomas Soome 		break;
94229a77b73SToomas Soome 
94329a77b73SToomas Soome 	default:
94429a77b73SToomas Soome 		bcons_dev.bd_putchar(c);
94529a77b73SToomas Soome 		break;
94629a77b73SToomas Soome 	}
94729a77b73SToomas Soome }
94829a77b73SToomas Soome 
94929a77b73SToomas Soome /*
95029a77b73SToomas Soome  * if parameters [0..count - 1] are not set, set them to the value
95129a77b73SToomas Soome  * of newparam.
95229a77b73SToomas Soome  */
95329a77b73SToomas Soome static void
95429a77b73SToomas Soome btem_setparam(btem_state_t *btem, int count, int newparam)
95529a77b73SToomas Soome {
95629a77b73SToomas Soome 	int i;
95729a77b73SToomas Soome 
95829a77b73SToomas Soome 	for (i = 0; i < count; i++) {
95929a77b73SToomas Soome 		if (btem->btem_params[i] == -1)
96029a77b73SToomas Soome 			btem->btem_params[i] = newparam;
96129a77b73SToomas Soome 	}
96229a77b73SToomas Soome }
96329a77b73SToomas Soome 
96429a77b73SToomas Soome static void
96529a77b73SToomas Soome btem_chkparam(btem_state_t *btem, int c)
96629a77b73SToomas Soome {
96729a77b73SToomas Soome 	int rows, cols;
96829a77b73SToomas Soome 
96929a77b73SToomas Soome 	rows = fb_info.cursor.pos.y;
97029a77b73SToomas Soome 	cols = fb_info.cursor.pos.x;
97129a77b73SToomas Soome 	switch (c) {
97229a77b73SToomas Soome 	case '@':			/* insert char */
97329a77b73SToomas Soome 		btem_setparam(btem, 1, 1);
97429a77b73SToomas Soome 		bcons_dev.bd_shift(btem->btem_params[0]);
97529a77b73SToomas Soome 		break;
97629a77b73SToomas Soome 
97729a77b73SToomas Soome 	case 'A':			/* cursor up */
97829a77b73SToomas Soome 		btem_setparam(btem, 1, 1);
97929a77b73SToomas Soome 		bcons_dev.bd_setpos(rows - btem->btem_params[0], cols);
98029a77b73SToomas Soome 		break;
98129a77b73SToomas Soome 
98229a77b73SToomas Soome 	case 'B':			/* cursor down */
98329a77b73SToomas Soome 		btem_setparam(btem, 1, 1);
98429a77b73SToomas Soome 		bcons_dev.bd_setpos(rows + btem->btem_params[0], cols);
98529a77b73SToomas Soome 		break;
98629a77b73SToomas Soome 
98729a77b73SToomas Soome 	case 'C':			/* cursor right */
98829a77b73SToomas Soome 		btem_setparam(btem, 1, 1);
98929a77b73SToomas Soome 		bcons_dev.bd_setpos(rows, cols + btem->btem_params[0]);
99029a77b73SToomas Soome 		break;
99129a77b73SToomas Soome 
99229a77b73SToomas Soome 	case 'D':			/* cursor left */
99329a77b73SToomas Soome 		btem_setparam(btem, 1, 1);
99429a77b73SToomas Soome 		bcons_dev.bd_setpos(rows, cols - btem->btem_params[0]);
99529a77b73SToomas Soome 		break;
99629a77b73SToomas Soome 
99729a77b73SToomas Soome 	case 'K':
99829a77b73SToomas Soome 		bcons_dev.bd_eraseline();
99929a77b73SToomas Soome 		break;
100029a77b73SToomas Soome 	default:
100129a77b73SToomas Soome 		/* bcons_dev.bd_putchar(c); */
100229a77b73SToomas Soome 		break;
100329a77b73SToomas Soome 	}
100429a77b73SToomas Soome 	btem->btem_state = A_STATE_START;
100529a77b73SToomas Soome }
100629a77b73SToomas Soome 
100729a77b73SToomas Soome static void
100829a77b73SToomas Soome btem_getparams(btem_state_t *btem, int c)
100929a77b73SToomas Soome {
101029a77b73SToomas Soome 	if (isdigit(c)) {
101129a77b73SToomas Soome 		btem->btem_paramval = btem->btem_paramval * 10 + c - '0';
101229a77b73SToomas Soome 		btem->btem_gotparam = B_TRUE;
101329a77b73SToomas Soome 		return;
101429a77b73SToomas Soome 	}
101529a77b73SToomas Soome 
101629a77b73SToomas Soome 	if (btem->btem_curparam < BTEM_MAXPARAMS) {
101729a77b73SToomas Soome 		if (btem->btem_gotparam == B_TRUE) {
101829a77b73SToomas Soome 			btem->btem_params[btem->btem_curparam] =
101929a77b73SToomas Soome 			    btem->btem_paramval;
102029a77b73SToomas Soome 		}
102129a77b73SToomas Soome 		btem->btem_curparam++;
102229a77b73SToomas Soome 	}
102329a77b73SToomas Soome 
102429a77b73SToomas Soome 	if (c == ';') {
102529a77b73SToomas Soome 		/* Restart parameter search */
102629a77b73SToomas Soome 		btem->btem_gotparam = B_FALSE;
102729a77b73SToomas Soome 		btem->btem_paramval = 0;
102829a77b73SToomas Soome 	} else {
102929a77b73SToomas Soome 		btem_chkparam(btem, c);
103029a77b73SToomas Soome 	}
103129a77b73SToomas Soome }
103229a77b73SToomas Soome 
103329a77b73SToomas Soome /* Simple boot terminal parser. */
103429a77b73SToomas Soome static void
103529a77b73SToomas Soome btem_parse(btem_state_t *btem, int c)
103629a77b73SToomas Soome {
103729a77b73SToomas Soome 	int i;
103829a77b73SToomas Soome 
103929a77b73SToomas Soome 	/* Normal state? */
104029a77b73SToomas Soome 	if (btem->btem_state == A_STATE_START) {
104129a77b73SToomas Soome 		if (c == A_CSI || c < ' ')
104229a77b73SToomas Soome 			btem_control(btem, c);
104329a77b73SToomas Soome 		else
104429a77b73SToomas Soome 			bcons_dev.bd_putchar(c);
104529a77b73SToomas Soome 		return;
104629a77b73SToomas Soome 	}
104729a77b73SToomas Soome 
104829a77b73SToomas Soome 	/* In <ESC> sequence */
104929a77b73SToomas Soome 	if (btem->btem_state != A_STATE_ESC) {
105029a77b73SToomas Soome 		btem_getparams(btem, c);
105129a77b73SToomas Soome 		return;
105229a77b73SToomas Soome 	}
105329a77b73SToomas Soome 
105429a77b73SToomas Soome 	/* Previous char was <ESC> */
105529a77b73SToomas Soome 	switch (c) {
105629a77b73SToomas Soome 	case '[':
105729a77b73SToomas Soome 		btem->btem_curparam = 0;
105829a77b73SToomas Soome 		btem->btem_paramval = 0;
105929a77b73SToomas Soome 		btem->btem_gotparam = B_FALSE;
106029a77b73SToomas Soome 		/* clear the parameters */
106129a77b73SToomas Soome 		for (i = 0; i < BTEM_MAXPARAMS; i++)
106229a77b73SToomas Soome 			btem->btem_params[i] = -1;
106329a77b73SToomas Soome 		btem->btem_state = A_STATE_CSI;
106429a77b73SToomas Soome 		return;
106529a77b73SToomas Soome 
106629a77b73SToomas Soome 	case 'Q':	/* <ESC>Q */
106729a77b73SToomas Soome 	case 'C':	/* <ESC>C */
106829a77b73SToomas Soome 		btem->btem_state = A_STATE_START;
106929a77b73SToomas Soome 		return;
107029a77b73SToomas Soome 
107129a77b73SToomas Soome 	default:
107229a77b73SToomas Soome 		btem->btem_state = A_STATE_START;
107329a77b73SToomas Soome 		break;
107429a77b73SToomas Soome 	}
107529a77b73SToomas Soome 
107629a77b73SToomas Soome 	if (c < ' ')
107729a77b73SToomas Soome 		btem_control(btem, c);
107829a77b73SToomas Soome 	else
107929a77b73SToomas Soome 		bcons_dev.bd_putchar(c);
108029a77b73SToomas Soome }
108129a77b73SToomas Soome 
1082ae115bc7Smrj static void
108360cbda0dSToomas Soome _doputchar(int device, int c)
1084ae115bc7Smrj {
108560cbda0dSToomas Soome 	switch (device) {
10860d928757SGary Mills 	case CONS_TTY:
1087ae115bc7Smrj 		serial_putchar(c);
1088ae115bc7Smrj 		return;
1089ae115bc7Smrj 	case CONS_SCREEN_TEXT:
10908e6d016fSToomas Soome 	case CONS_FRAMEBUFFER:
109129a77b73SToomas Soome 		bcons_dev.bd_cursor(B_FALSE);
109229a77b73SToomas Soome 		btem_parse(&boot_tem, c);
109329a77b73SToomas Soome 		bcons_dev.bd_cursor(B_TRUE);
10948e6d016fSToomas Soome 		return;
109567ce1dadSJan Setje-Eilers 	case CONS_SCREEN_GRAPHICS:
1096ae115bc7Smrj #if !defined(_BOOT)
1097ae115bc7Smrj 	case CONS_USBSER:
109848633f18SJan Setje-Eilers 		defcons_putchar(c);
1099ae115bc7Smrj #endif /* _BOOT */
110060cbda0dSToomas Soome 	default:
110148633f18SJan Setje-Eilers 		return;
1102ae115bc7Smrj 	}
1103ae115bc7Smrj }
1104ae115bc7Smrj 
1105ae115bc7Smrj void
1106ae115bc7Smrj bcons_putchar(int c)
1107ae115bc7Smrj {
1108843e1988Sjohnlev #if defined(__xpv)
1109843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1110843e1988Sjohnlev 	    console == CONS_HYPERVISOR) {
1111843e1988Sjohnlev 		bcons_putchar_xen(c);
1112843e1988Sjohnlev 		return;
1113843e1988Sjohnlev 	}
1114843e1988Sjohnlev #endif /* __xpv */
1115843e1988Sjohnlev 
111629a77b73SToomas Soome 	if (c == '\n') {
111729a77b73SToomas Soome 		_doputchar(console, '\r');
111860cbda0dSToomas Soome 		if (diag != console)
111929a77b73SToomas Soome 			_doputchar(diag, '\r');
1120ae115bc7Smrj 	}
112160cbda0dSToomas Soome 	_doputchar(console, c);
112260cbda0dSToomas Soome 	if (diag != console)
112360cbda0dSToomas Soome 		_doputchar(diag, c);
1124ae115bc7Smrj }
1125ae115bc7Smrj 
1126ae115bc7Smrj /*
1127ae115bc7Smrj  * kernel character input functions
1128ae115bc7Smrj  */
1129ae115bc7Smrj int
1130ae115bc7Smrj bcons_getchar(void)
1131ae115bc7Smrj {
1132843e1988Sjohnlev #if defined(__xpv)
1133843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1134843e1988Sjohnlev 	    console == CONS_HYPERVISOR)
1135843e1988Sjohnlev 		return (bcons_getchar_xen());
1136843e1988Sjohnlev #endif /* __xpv */
1137843e1988Sjohnlev 
113860cbda0dSToomas Soome 	for (;;) {
113960cbda0dSToomas Soome 		if (console == CONS_TTY || diag == CONS_TTY) {
114060cbda0dSToomas Soome 			if (serial_ischar())
114160cbda0dSToomas Soome 				return (serial_getchar());
114260cbda0dSToomas Soome 		}
114360cbda0dSToomas Soome 		if (console != CONS_INVALID || diag != CONS_INVALID) {
114460cbda0dSToomas Soome 			if (kb_ischar())
114560cbda0dSToomas Soome 				return (kb_getchar());
114660cbda0dSToomas Soome 		}
1147ae115bc7Smrj 	}
1148ae115bc7Smrj }
1149ae115bc7Smrj 
11502e6e9b6bSJohn Levon /*
11512e6e9b6bSJohn Levon  * Nothing below is used by dboot.
11522e6e9b6bSJohn Levon  */
1153ae115bc7Smrj #if !defined(_BOOT)
1154ae115bc7Smrj 
1155ae115bc7Smrj int
1156ae115bc7Smrj bcons_ischar(void)
1157ae115bc7Smrj {
115860cbda0dSToomas Soome 	int c = 0;
1159843e1988Sjohnlev 
1160843e1988Sjohnlev #if defined(__xpv)
1161843e1988Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
1162843e1988Sjohnlev 	    console == CONS_HYPERVISOR)
1163843e1988Sjohnlev 		return (bcons_ischar_xen());
1164843e1988Sjohnlev #endif /* __xpv */
1165843e1988Sjohnlev 
1166ae115bc7Smrj 	switch (console) {
11670d928757SGary Mills 	case CONS_TTY:
116860cbda0dSToomas Soome 		c = serial_ischar();
116960cbda0dSToomas Soome 		break;
117060cbda0dSToomas Soome 
117160cbda0dSToomas Soome 	case CONS_INVALID:
117260cbda0dSToomas Soome 		break;
117360cbda0dSToomas Soome 
117460cbda0dSToomas Soome 	default:
117560cbda0dSToomas Soome 		c = kb_ischar();
117660cbda0dSToomas Soome 	}
117760cbda0dSToomas Soome 	if (c != 0)
117860cbda0dSToomas Soome 		return (c);
117960cbda0dSToomas Soome 
118060cbda0dSToomas Soome 	switch (diag) {
118160cbda0dSToomas Soome 	case CONS_TTY:
118260cbda0dSToomas Soome 		c = serial_ischar();
118360cbda0dSToomas Soome 		break;
118460cbda0dSToomas Soome 
118560cbda0dSToomas Soome 	case CONS_INVALID:
118660cbda0dSToomas Soome 		break;
118760cbda0dSToomas Soome 
1188ae115bc7Smrj 	default:
118960cbda0dSToomas Soome 		c = kb_ischar();
1190ae115bc7Smrj 	}
119160cbda0dSToomas Soome 
119260cbda0dSToomas Soome 	return (c);
1193ae115bc7Smrj }
1194ae115bc7Smrj 
11952e6e9b6bSJohn Levon /*
11962e6e9b6bSJohn Levon  * 2nd part of console initialization: we've now processed bootenv.rc; update
11972e6e9b6bSJohn Levon  * console settings as appropriate. This only really processes serial console
11982e6e9b6bSJohn Levon  * modifications.
11992e6e9b6bSJohn Levon  */
12002e6e9b6bSJohn Levon void
12012e6e9b6bSJohn Levon bcons_post_bootenvrc(char *inputdev, char *outputdev, char *consoledev)
12022e6e9b6bSJohn Levon {
12032e6e9b6bSJohn Levon 	int cons = CONS_INVALID;
12042e6e9b6bSJohn Levon 	int ttyn;
12052e6e9b6bSJohn Levon 	char *devnames[] = { consoledev, outputdev, inputdev, NULL };
12062e6e9b6bSJohn Levon 	int i;
12072e6e9b6bSJohn Levon 	extern int post_fastreboot;
12082e6e9b6bSJohn Levon 
1209*584b574aSToomas Soome 	ttyn = 0;
12102e6e9b6bSJohn Levon 	if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
12112e6e9b6bSJohn Levon 		console = CONS_SCREEN_TEXT;
12122e6e9b6bSJohn Levon 
12132e6e9b6bSJohn Levon 	/*
12142e6e9b6bSJohn Levon 	 * USB serial and GRAPHICS console: we just collect data into a buffer.
12152e6e9b6bSJohn Levon 	 */
12162e6e9b6bSJohn Levon 	if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) {
12172e6e9b6bSJohn Levon 		extern void *defcons_init(size_t);
12182e6e9b6bSJohn Levon 		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
12192e6e9b6bSJohn Levon 		return;
12202e6e9b6bSJohn Levon 	}
12212e6e9b6bSJohn Levon 
12222e6e9b6bSJohn Levon 	for (i = 0; devnames[i] != NULL; i++) {
12232e6e9b6bSJohn Levon 		cons = lookup_console_device(devnames[i], &ttyn);
12242e6e9b6bSJohn Levon 		if (cons != CONS_INVALID)
12252e6e9b6bSJohn Levon 			break;
12262e6e9b6bSJohn Levon 	}
12272e6e9b6bSJohn Levon 
12282e6e9b6bSJohn Levon 	if (cons == CONS_INVALID) {
12292e6e9b6bSJohn Levon 		/*
12302e6e9b6bSJohn Levon 		 * No console change, but let's see if bootenv.rc had a mode
12312e6e9b6bSJohn Levon 		 * setting we should apply.
12322e6e9b6bSJohn Levon 		 */
12332e6e9b6bSJohn Levon 		if (console == CONS_TTY && !bootprop_set_tty_mode)
12342e6e9b6bSJohn Levon 			serial_init();
12352e6e9b6bSJohn Levon 		return;
12362e6e9b6bSJohn Levon 	}
12372e6e9b6bSJohn Levon 
12382e6e9b6bSJohn Levon #if defined(__xpv)
12392e6e9b6bSJohn Levon 	/*
12402e6e9b6bSJohn Levon 	 * if the hypervisor is using the currently selected console device then
12412e6e9b6bSJohn Levon 	 * default to using the hypervisor as the console device.
12422e6e9b6bSJohn Levon 	 */
12432e6e9b6bSJohn Levon 	if (cons == console_hypervisor_device) {
12442e6e9b6bSJohn Levon 		cons = CONS_HYPERVISOR;
12452e6e9b6bSJohn Levon 		console_hypervisor_redirect = B_TRUE;
12462e6e9b6bSJohn Levon 	}
12472e6e9b6bSJohn Levon #endif /* __xpv */
12482e6e9b6bSJohn Levon 
12492e6e9b6bSJohn Levon 	console = cons;
12502e6e9b6bSJohn Levon 
12512e6e9b6bSJohn Levon 	if (console == CONS_TTY) {
12522e6e9b6bSJohn Levon 		tty_num = ttyn;
12532e6e9b6bSJohn Levon 		serial_init();
12542e6e9b6bSJohn Levon 	}
12552e6e9b6bSJohn Levon }
12562e6e9b6bSJohn Levon 
12572e6e9b6bSJohn Levon #if defined(__xpv)
12582e6e9b6bSJohn Levon boolean_t
12592e6e9b6bSJohn Levon bcons_hypervisor_redirect(void)
12602e6e9b6bSJohn Levon {
12612e6e9b6bSJohn Levon 	return (console_hypervisor_redirect);
12622e6e9b6bSJohn Levon }
12632e6e9b6bSJohn Levon 
12642e6e9b6bSJohn Levon void
12652e6e9b6bSJohn Levon bcons_device_change(int new_console)
12662e6e9b6bSJohn Levon {
12672e6e9b6bSJohn Levon 	if (new_console < CONS_MIN || new_console > CONS_MAX)
12682e6e9b6bSJohn Levon 		return;
12692e6e9b6bSJohn Levon 
12702e6e9b6bSJohn Levon 	/*
12712e6e9b6bSJohn Levon 	 * If we are asked to switch the console to the hypervisor, that
12722e6e9b6bSJohn Levon 	 * really means to switch the console to whichever device the
12732e6e9b6bSJohn Levon 	 * hypervisor is/was using.
12742e6e9b6bSJohn Levon 	 */
12752e6e9b6bSJohn Levon 	if (new_console == CONS_HYPERVISOR)
12762e6e9b6bSJohn Levon 		new_console = console_hypervisor_device;
12772e6e9b6bSJohn Levon 
12782e6e9b6bSJohn Levon 	console = new_console;
12792e6e9b6bSJohn Levon 
12802e6e9b6bSJohn Levon 	if (new_console == CONS_TTY) {
12812e6e9b6bSJohn Levon 		tty_num = console_hypervisor_tty_num;
12822e6e9b6bSJohn Levon 		serial_init();
12832e6e9b6bSJohn Levon 	}
12842e6e9b6bSJohn Levon }
12852e6e9b6bSJohn Levon #endif /* __xpv */
12862e6e9b6bSJohn Levon 
12872e6e9b6bSJohn Levon static void
12882e6e9b6bSJohn Levon defcons_putchar(int c)
12892e6e9b6bSJohn Levon {
12902e6e9b6bSJohn Levon 	if (defcons_buf != NULL &&
12912e6e9b6bSJohn Levon 	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
12922e6e9b6bSJohn Levon 		*defcons_cur++ = c;
12932e6e9b6bSJohn Levon 		*defcons_cur = 0;
12942e6e9b6bSJohn Levon 	}
12952e6e9b6bSJohn Levon }
12962e6e9b6bSJohn Levon 
1297ae115bc7Smrj #endif /* _BOOT */
1298