9929 uts: boot console mirror with diag-device
Reviewed by: John Levon <john.levon@joyent.com>
Approved by: Joshua M. Clulow <josh@sysmgr.org>
diff --git a/usr/src/uts/i86pc/boot/boot_console.c b/usr/src/uts/i86pc/boot/boot_console.c
index e1504b4..e5d8e73 100644
--- a/usr/src/uts/i86pc/boot/boot_console.c
+++ b/usr/src/uts/i86pc/boot/boot_console.c
@@ -59,6 +59,7 @@
static int cons_color = CONS_COLOR;
static int console = CONS_SCREEN_TEXT;
+static int diag = CONS_INVALID;
static int tty_num = 0;
static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
static char *boot_line;
@@ -607,11 +608,45 @@
boot_env.be_size = modules[i].bm_size;
}
+/*
+ * 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.
+ *
+ * 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.
+ */
+static int
+lookup_console_devices(const char *cons_str)
+{
+ int n, cons;
+ size_t len, cons_len;
+ console_value_t *consolep;
+
+ cons = CONS_INVALID;
+ if (cons_str != NULL) {
+
+ cons_len = strlen(cons_str);
+ for (n = 0; console_devices[n].name != NULL; n++) {
+ consolep = &console_devices[n];
+ len = strlen(consolep->name);
+ if ((len <= cons_len) && ((cons_str[len] == '\0') ||
+ (cons_str[len] == ',') || (cons_str[len] == '\'') ||
+ (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
+ (strncmp(cons_str, consolep->name, len) == 0)) {
+ cons = consolep->value;
+ if (cons == CONS_TTY)
+ tty_num = n;
+ break;
+ }
+ }
+ }
+ return (cons);
+}
+
void
bcons_init(struct xboot_info *xbi)
{
- console_value_t *consolep;
- size_t len, cons_len;
const char *cons_str;
#if !defined(_BOOT)
static char console_text[] = "text";
@@ -634,6 +669,13 @@
bcons_init_xen(boot_line);
#endif /* __xpv */
+ /*
+ * First check for diag-device.
+ */
+ cons_str = find_boot_prop("diag-device");
+ if (cons_str != NULL)
+ diag = lookup_console_devices(cons_str);
+
cons_str = find_boot_prop("console");
if (cons_str == NULL)
cons_str = find_boot_prop("output-device");
@@ -643,29 +685,8 @@
cons_str = console_text;
#endif
- /*
- * 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.
- */
- if (cons_str != NULL) {
- int n;
-
- cons_len = strlen(cons_str);
- for (n = 0; console_devices[n].name != NULL; n++) {
- consolep = &console_devices[n];
- len = strlen(consolep->name);
- if ((len <= cons_len) && ((cons_str[len] == '\0') ||
- (cons_str[len] == ',') || (cons_str[len] == '\'') ||
- (cons_str[len] == '"') || ISSPACE(cons_str[len])) &&
- (strncmp(cons_str, consolep->name, len) == 0)) {
- console = consolep->value;
- if (console == CONS_TTY)
- tty_num = n;
- break;
- }
- }
- }
+ if (cons_str != NULL)
+ console = lookup_console_devices(cons_str);
#if defined(__xpv)
/*
@@ -751,6 +772,24 @@
kb_init();
break;
}
+
+ /*
+ * Initialize diag device unless already done.
+ */
+ switch (diag) {
+ case CONS_TTY:
+ if (console != CONS_TTY)
+ serial_init();
+ break;
+ case CONS_SCREEN_GRAPHICS:
+ case CONS_SCREEN_TEXT:
+ if (console != CONS_SCREEN_GRAPHICS &&
+ console != CONS_SCREEN_TEXT)
+ kb_init();
+ break;
+ default:
+ break;
+ }
}
#if !defined(_BOOT)
@@ -916,9 +955,9 @@
}
static void
-_doputchar(int c)
+_doputchar(int device, int c)
{
- switch (console) {
+ switch (device) {
case CONS_TTY:
serial_putchar(c);
return;
@@ -930,6 +969,7 @@
case CONS_USBSER:
defcons_putchar(c);
#endif /* _BOOT */
+ default:
return;
}
}
@@ -949,23 +989,33 @@
if (c == '\t') {
do {
- _doputchar(' ');
+ _doputchar(console, ' ');
+ if (diag != console)
+ _doputchar(diag, ' ');
} while (++bhcharpos % 8);
return;
} else if (c == '\n' || c == '\r') {
bhcharpos = 0;
- _doputchar('\r');
- _doputchar(c);
+ _doputchar(console, '\r');
+ _doputchar(console, c);
+ if (diag != console) {
+ _doputchar(diag, '\r');
+ _doputchar(diag, c);
+ }
return;
} else if (c == '\b') {
if (bhcharpos)
bhcharpos--;
- _doputchar(c);
+ _doputchar(console, c);
+ if (diag != console)
+ _doputchar(diag, c);
return;
}
bhcharpos++;
- _doputchar(c);
+ _doputchar(console, c);
+ if (diag != console)
+ _doputchar(diag, c);
}
/*
@@ -980,11 +1030,15 @@
return (bcons_getchar_xen());
#endif /* __xpv */
- switch (console) {
- case CONS_TTY:
- return (serial_getchar());
- default:
- return (kb_getchar());
+ for (;;) {
+ if (console == CONS_TTY || diag == CONS_TTY) {
+ if (serial_ischar())
+ return (serial_getchar());
+ }
+ if (console != CONS_INVALID || diag != CONS_INVALID) {
+ if (kb_ischar())
+ return (kb_getchar());
+ }
}
}
@@ -993,6 +1047,7 @@
int
bcons_ischar(void)
{
+ int c = 0;
#if defined(__xpv)
if (!DOMAIN_IS_INITDOMAIN(xen_info) ||
@@ -1002,10 +1057,31 @@
switch (console) {
case CONS_TTY:
- return (serial_ischar());
+ c = serial_ischar();
+ break;
+
+ case CONS_INVALID:
+ break;
+
default:
- return (kb_ischar());
+ c = kb_ischar();
}
+ if (c != 0)
+ return (c);
+
+ switch (diag) {
+ case CONS_TTY:
+ c = serial_ischar();
+ break;
+
+ case CONS_INVALID:
+ break;
+
+ default:
+ c = kb_ischar();
+ }
+
+ return (c);
}
#endif /* _BOOT */