--- old/usr/src/uts/common/krtld/kobj.c	Tue Jan 21 15:29:48 2020
+++ new/usr/src/uts/common/krtld/kobj.c	Tue Jan 21 15:29:48 2020
@@ -25,7 +25,7 @@
 /*
  * Copyright 2011 Bayard G. Bell <buffer.g.overflow@gmail.com>.
  * All rights reserved. Use is subject to license terms.
- * Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  */
 
 /*
@@ -423,7 +423,7 @@
 		 * Now that the ramdisk is mounted, finish boot property
 		 * initialization.
 		 */
-		boot_prop_finish();
+		read_bootenvrc();
 	}
 
 #if !defined(_UNIX_KRTLD)
--- old/usr/src/uts/i86pc/boot/boot_console.c	Tue Jan 21 15:29:48 2020
+++ new/usr/src/uts/i86pc/boot/boot_console.c	Tue Jan 21 15:29:48 2020
@@ -20,11 +20,17 @@
  */
 /*
  * Copyright (c) 2012 Gary Mills
+ * Copyright 2020 Joyent, Inc.
  *
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+/*
+ * Boot console support.  Most of the file is shared between dboot, and the
+ * early kernel / fakebop.
+ */
+
 #include <sys/types.h>
 #include <sys/systm.h>
 #include <sys/archsystm.h>
@@ -101,9 +107,10 @@
 static void serial_putchar(int);
 static void serial_adjust_prop(void);
 
+static void defcons_putchar(int);
+
 #if !defined(_BOOT)
-/* Set if the console or mode are expressed in the boot line */
-static int console_set, console_mode_set;
+static boolean_t bootprop_set_tty_mode;
 #endif
 
 #if defined(__xpv)
@@ -410,12 +417,12 @@
 	(void) strcpy(propname, "ttyX-mode");
 	propname[3] = 'a' + tty_num;
 	propval = get_mode_value(propname);
-	if (propval == NULL)
-		propval = "9600,8,n,1,-";
 #if !defined(_BOOT)
-	else
-		console_mode_set = 1;
+	if (propval != NULL)
+		bootprop_set_tty_mode = B_TRUE;
 #endif
+	if (propval == NULL)
+		propval = "9600,8,n,1,-";
 
 	/* property is of the form: "9600,8,n,1,-" */
 	p = propval;
@@ -680,15 +687,14 @@
 }
 
 /*
- * Go through the console_devices array trying to match the string
- * we were given.  The string on the command line must end with
- * a comma or white space.
+ * Go through the known console device names trying to match the string we were
+ * given.  The string on the command line must end with a comma or white space.
  *
- * This function does set tty_num as an side effect, this does imply that
- * only one of the main console and the diag-device can be using serial.
+ * For convenience, we provide the caller with an integer index for the CONS_TTY
+ * case.
  */
 static int
-lookup_console_devices(const char *cons_str)
+lookup_console_device(const char *cons_str, int *indexp)
 {
 	int n, cons;
 	size_t len, cons_len;
@@ -707,7 +713,7 @@
 			    (strncmp(cons_str, consolep->name, len) == 0)) {
 				cons = consolep->value;
 				if (cons == CONS_TTY)
-					tty_num = n;
+					*indexp = n;
 				break;
 			}
 		}
@@ -748,7 +754,7 @@
 	 */
 	cons_str = find_boot_prop("diag-device");
 	if (cons_str != NULL)
-		diag = lookup_console_devices(cons_str);
+		diag = lookup_console_device(cons_str, &tty_num);
 
 	cons_str = find_boot_prop("console");
 	if (cons_str == NULL)
@@ -760,7 +766,7 @@
 #endif
 
 	if (cons_str != NULL)
-		console = lookup_console_devices(cons_str);
+		console = lookup_console_device(cons_str, &tty_num);
 
 #if defined(__xpv)
 	/*
@@ -773,16 +779,8 @@
 	}
 #endif /* __xpv */
 
-	/*
-	 * If no console device specified, default to text.
-	 * Remember what was specified for second phase.
-	 */
 	if (console == CONS_INVALID)
 		console = CONS_SCREEN_TEXT;
-#if !defined(_BOOT)
-	else
-		console_set = 1;
-#endif
 
 #if defined(__xpv)
 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
@@ -867,131 +865,7 @@
 	}
 }
 
-#if !defined(_BOOT)
-/*
- * 2nd part of console initialization.
- * In the kernel (ie. fakebop), this can be used only to switch to
- * using a serial port instead of screen based on the contents
- * of the bootenv.rc file.
- */
-/*ARGSUSED*/
-void
-bcons_init2(char *inputdev, char *outputdev, char *consoledev)
-{
-	int cons = CONS_INVALID;
-	int ttyn;
-	char *devnames[] = { consoledev, outputdev, inputdev, NULL };
-	console_value_t *consolep;
-	int i;
-	extern int post_fastreboot;
-
-	if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
-		console = CONS_SCREEN_TEXT;
-
-	if (console != CONS_USBSER && console != CONS_SCREEN_GRAPHICS) {
-		if (console_set) {
-			/*
-			 * If the console was set on the command line,
-			 * but the ttyX-mode was not, we only need to
-			 * check bootenv.rc for that setting.
-			 */
-			if ((!console_mode_set) && (console == CONS_TTY))
-				serial_init();
-			return;
-		}
-
-		for (i = 0; devnames[i] != NULL; i++) {
-			int n;
-
-			for (n = 0; console_devices[n].name != NULL; n++) {
-				consolep = &console_devices[n];
-				if (strcmp(devnames[i], consolep->name) == 0) {
-					cons = consolep->value;
-					if (cons == CONS_TTY)
-						ttyn = n;
-				}
-			}
-			if (cons != CONS_INVALID)
-				break;
-		}
-
-#if defined(__xpv)
-		/*
-		 * if the hypervisor is using the currently selected console
-		 * device then default to using the hypervisor as the console
-		 * device.
-		 */
-		if (cons == console_hypervisor_device) {
-			cons = CONS_HYPERVISOR;
-			console_hypervisor_redirect = B_TRUE;
-		}
-#endif /* __xpv */
-
-		if ((cons == CONS_INVALID) || (cons == console)) {
-			/*
-			 * we're sticking with whatever the current setting is
-			 */
-			return;
-		}
-
-		console = cons;
-		if (cons == CONS_TTY) {
-			tty_num = ttyn;
-			serial_init();
-			return;
-		}
-	} else {
-		/*
-		 * USB serial and GRAPHICS console
-		 * we just collect data into a buffer
-		 */
-		extern void *defcons_init(size_t);
-		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
-	}
-}
-
-#if defined(__xpv)
-boolean_t
-bcons_hypervisor_redirect(void)
-{
-	return (console_hypervisor_redirect);
-}
-
-void
-bcons_device_change(int new_console)
-{
-	if (new_console < CONS_MIN || new_console > CONS_MAX)
-		return;
-
-	/*
-	 * If we are asked to switch the console to the hypervisor, that
-	 * really means to switch the console to whichever device the
-	 * hypervisor is/was using.
-	 */
-	if (new_console == CONS_HYPERVISOR)
-		new_console = console_hypervisor_device;
-
-	console = new_console;
-
-	if (new_console == CONS_TTY) {
-		tty_num = console_hypervisor_tty_num;
-		serial_init();
-	}
-}
-#endif /* __xpv */
-
 static void
-defcons_putchar(int c)
-{
-	if (defcons_buf != NULL &&
-	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
-		*defcons_cur++ = c;
-		*defcons_cur = 0;
-	}
-}
-#endif	/* _BOOT */
-
-static void
 serial_putchar(int c)
 {
 	int checks = 10000;
@@ -1273,6 +1147,9 @@
 	}
 }
 
+/*
+ * Nothing below is used by dboot.
+ */
 #if !defined(_BOOT)
 
 int
@@ -1315,4 +1192,106 @@
 	return (c);
 }
 
+/*
+ * 2nd part of console initialization: we've now processed bootenv.rc; update
+ * console settings as appropriate. This only really processes serial console
+ * modifications.
+ */
+void
+bcons_post_bootenvrc(char *inputdev, char *outputdev, char *consoledev)
+{
+	int cons = CONS_INVALID;
+	int ttyn;
+	char *devnames[] = { consoledev, outputdev, inputdev, NULL };
+	console_value_t *consolep;
+	int i;
+	extern int post_fastreboot;
+
+	if (post_fastreboot && console == CONS_SCREEN_GRAPHICS)
+		console = CONS_SCREEN_TEXT;
+
+	/*
+	 * USB serial and GRAPHICS console: we just collect data into a buffer.
+	 */
+	if (console == CONS_USBSER || console == CONS_SCREEN_GRAPHICS) {
+		extern void *defcons_init(size_t);
+		defcons_buf = defcons_cur = defcons_init(MMU_PAGESIZE);
+		return;
+	}
+
+	for (i = 0; devnames[i] != NULL; i++) {
+		cons = lookup_console_device(devnames[i], &ttyn);
+		if (cons != CONS_INVALID)
+			break;
+	}
+
+	if (cons == CONS_INVALID) {
+		/*
+		 * No console change, but let's see if bootenv.rc had a mode
+		 * setting we should apply.
+		 */
+		if (console == CONS_TTY && !bootprop_set_tty_mode)
+			serial_init();
+		return;
+	}
+
+#if defined(__xpv)
+	/*
+	 * if the hypervisor is using the currently selected console device then
+	 * default to using the hypervisor as the console device.
+	 */
+	if (cons == console_hypervisor_device) {
+		cons = CONS_HYPERVISOR;
+		console_hypervisor_redirect = B_TRUE;
+	}
+#endif /* __xpv */
+
+	console = cons;
+
+	if (console == CONS_TTY) {
+		tty_num = ttyn;
+		serial_init();
+	}
+}
+
+#if defined(__xpv)
+boolean_t
+bcons_hypervisor_redirect(void)
+{
+	return (console_hypervisor_redirect);
+}
+
+void
+bcons_device_change(int new_console)
+{
+	if (new_console < CONS_MIN || new_console > CONS_MAX)
+		return;
+
+	/*
+	 * If we are asked to switch the console to the hypervisor, that
+	 * really means to switch the console to whichever device the
+	 * hypervisor is/was using.
+	 */
+	if (new_console == CONS_HYPERVISOR)
+		new_console = console_hypervisor_device;
+
+	console = new_console;
+
+	if (new_console == CONS_TTY) {
+		tty_num = console_hypervisor_tty_num;
+		serial_init();
+	}
+}
+#endif /* __xpv */
+
+static void
+defcons_putchar(int c)
+{
+	if (defcons_buf != NULL &&
+	    defcons_cur + 1 - defcons_buf < MMU_PAGESIZE) {
+		*defcons_cur++ = c;
+		*defcons_cur = 0;
+	}
+}
+
 #endif /* _BOOT */
--- old/usr/src/uts/i86pc/os/fakebop.c	Tue Jan 21 15:29:48 2020
+++ new/usr/src/uts/i86pc/os/fakebop.c	Tue Jan 21 15:29:48 2020
@@ -101,7 +101,7 @@
 
 /*
  * Boot info from "glue" code in low memory. xbootp is used by:
- *	do_bop_phys_alloc(), do_bsys_alloc() and boot_prop_finish().
+ *	do_bop_phys_alloc(), do_bsys_alloc() and read_bootenvrc().
  */
 static struct xboot_info *xbootp;
 static uintptr_t next_virt;	/* next available virtual address */
@@ -670,7 +670,7 @@
  * we do single character I/O since this is really just looking at memory
  */
 void
-boot_prop_finish(void)
+read_bootenvrc(void)
 {
 	int fd;
 	char *line;
@@ -778,17 +778,32 @@
 
 		/*
 		 * If a property was explicitly set on the command line
-		 * it will override a setting in bootenv.rc
+		 * it will override a setting in bootenv.rc. We make an
+		 * exception for a property from the bootloader such as:
+		 *
+		 * console="text,ttya,ttyb,ttyc,ttyd"
+		 *
+		 * In such a case, picking the first value here (as
+		 * lookup_console_devices() does) is at best a guess; if
+		 * bootenv.rc has a value, it's probably better.
 		 */
-		if (do_bsys_getproplen(NULL, name) >= 0)
+		if (strcmp(name, "console") == 0) {
+			char propval[BP_MAX_STRLEN] = "";
+
+			if (do_bsys_getprop(NULL, name, propval) == -1 ||
+			    strchr(propval, ',') != NULL)
+				bsetprops(name, value);
 			continue;
+		}
 
-		bsetprops(name, value);
+		if (do_bsys_getproplen(NULL, name) == -1)
+			bsetprops(name, value);
 	}
 done:
 	if (fd >= 0)
 		(void) BRD_CLOSE(bfs_ops, fd);
 
+
 	/*
 	 * Check if we have to limit the boot time allocator
 	 */
@@ -843,7 +858,7 @@
 			v_len = 0;
 		}
 		consoledev[v_len] = 0;
-		bcons_init2(inputdev, outputdev, consoledev);
+		bcons_post_bootenvrc(inputdev, outputdev, consoledev);
 	} else {
 		/*
 		 * Ensure console property exists
@@ -853,7 +868,7 @@
 		if (v_len < 0)
 			bsetprops("console", "hypervisor");
 		inputdev = outputdev = consoledev = "hypervisor";
-		bcons_init2(inputdev, outputdev, consoledev);
+		bcons_post_bootenvrc(inputdev, outputdev, consoledev);
 	}
 
 	if (find_boot_prop("prom_debug") || kbm_debug)
--- old/usr/src/uts/i86pc/sys/boot_console.h	Tue Jan 21 15:29:49 2020
+++ new/usr/src/uts/i86pc/sys/boot_console.h	Tue Jan 21 15:29:49 2020
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2012 Gary Mills
+ * Copyright 2020 Joyent, Inc.
  *
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -68,7 +69,7 @@
 extern int bcons_gets(char *, int);
 
 #if !defined(_BOOT)
-extern void bcons_init2(char *, char *, char *);
+extern void bcons_post_bootenvrc(char *, char *, char *);
 extern boolean_t bcons_hypervisor_redirect(void);
 extern void bcons_device_change(int);
 #endif /* !_BOOT */
--- old/usr/src/uts/intel/sys/bootconf.h	Tue Jan 21 15:29:49 2020
+++ new/usr/src/uts/intel/sys/bootconf.h	Tue Jan 21 15:29:49 2020
@@ -23,7 +23,7 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  * Copyright 2016 Nexenta Systems, Inc.
- * Copyright 2019, Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  */
 
 #ifndef	_SYS_BOOTCONF_H
@@ -243,7 +243,7 @@
     __KPRINTFLIKE(1) __NORETURN;
 #pragma rarely_called(bop_panic)
 
-extern void boot_prop_finish(void);
+extern void read_bootenvrc(void);
 
 extern int bootprop_getval(const char *, u_longlong_t *);
 extern int bootprop_getstr(const char *, char *, size_t);
