summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToomas Soome <tsoome@me.com>2017-01-21 16:45:38 +0200
committerJoshua M. Clulow <josh@sysmgr.org>2017-04-21 20:09:35 -0700
commitf289ce6eb03db0584699ec4fed88ef795a33dd79 (patch)
tree0a66edd02334955057d0d092c0dee7cdfcd633d9
parent76608ff7a54afda798e7fdc98681fb6d37322109 (diff)
downloadillumos-joyent-f289ce6eb03db0584699ec4fed88ef795a33dd79.tar.gz
7839 uts: implement boot environment support
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Approved by: Joshua M. Clulow <josh@sysmgr.org>
-rw-r--r--usr/src/uts/i86pc/boot/boot_console.c130
-rw-r--r--usr/src/uts/i86pc/dboot/dboot_startkern.c58
-rw-r--r--usr/src/uts/i86pc/os/fakebop.c138
-rw-r--r--usr/src/uts/i86pc/sys/boot_console.h7
-rw-r--r--usr/src/uts/intel/sys/bootinfo.h3
5 files changed, 300 insertions, 36 deletions
diff --git a/usr/src/uts/i86pc/boot/boot_console.c b/usr/src/uts/i86pc/boot/boot_console.c
index cadc735588..6b0873d656 100644
--- a/usr/src/uts/i86pc/boot/boot_console.c
+++ b/usr/src/uts/i86pc/boot/boot_console.c
@@ -61,6 +61,22 @@ static int cons_color = CONS_COLOR;
static int console = CONS_SCREEN_TEXT;
static int tty_num = 0;
static int tty_addr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
+static char *boot_line;
+static struct boot_env {
+ char *be_env; /* ends with double ascii nul */
+ size_t be_size; /* size of the environment, including nul */
+} boot_env;
+
+static int serial_ischar(void);
+static int serial_getchar(void);
+static void serial_putchar(int);
+static void serial_adjust_prop(void);
+
+#if !defined(_BOOT)
+/* Set if the console or mode are expressed in the boot line */
+static int console_set, console_mode_set;
+#endif
+
#if defined(__xpv)
static int console_hypervisor_redirect = B_FALSE;
static int console_hypervisor_device = CONS_INVALID;
@@ -76,18 +92,6 @@ console_hypervisor_dev_type(int *tnum)
}
#endif /* __xpv */
-static int serial_ischar(void);
-static int serial_getchar(void);
-static void serial_putchar(int);
-static void serial_adjust_prop(void);
-
-static char *boot_line = NULL;
-
-#if !defined(_BOOT)
-/* Set if the console or mode are expressed in the boot line */
-static int console_set, console_mode_set;
-#endif
-
/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
void
clear_screen(void)
@@ -328,6 +332,67 @@ out:
return (ret);
}
+/*
+ * Find prop from boot env module. The data in module is list of C strings
+ * name=value, the list is terminated by double nul.
+ */
+static const char *
+find_boot_env_prop(const char *name)
+{
+ char *ptr;
+ size_t len;
+ uintptr_t size;
+
+ if (boot_env.be_env == NULL)
+ return (NULL);
+
+ ptr = boot_env.be_env;
+ len = strlen(name);
+
+ /*
+ * Make sure we have at least len + 2 bytes in the environment.
+ * We are looking for name=value\0 constructs, and the environment
+ * itself is terminated by '\0'.
+ */
+ if (boot_env.be_size < len + 2)
+ return (NULL);
+
+ do {
+ if ((strncmp(ptr, name, len) == 0) && (ptr[len] == '=')) {
+ ptr += len + 1;
+ return (ptr);
+ }
+ /* find the first '\0' */
+ while (*ptr != '\0') {
+ ptr++;
+ size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
+ if (size > boot_env.be_size)
+ return (NULL);
+ }
+ ptr++;
+
+ /* If the remainder is shorter than name + 2, get out. */
+ size = (uintptr_t)ptr - (uintptr_t)boot_env.be_env;
+ if (boot_env.be_size - size < len + 2)
+ return (NULL);
+ } while (*ptr != '\0');
+ return (NULL);
+}
+
+/*
+ * Get prop value from either command line or boot environment.
+ * We always check kernel command line first, as this will keep the
+ * functionality and will allow user to override the values in environment.
+ */
+const char *
+find_boot_prop(const char *name)
+{
+ const char *value = find_boot_line_prop(name);
+
+ if (value == NULL)
+ value = find_boot_env_prop(name);
+ return (value);
+}
#define MATCHES(p, pat) \
(strncmp(p, pat, strlen(pat)) == 0 ? (p += strlen(pat), 1) : 0)
@@ -341,14 +406,14 @@ out:
/*
* find a tty mode property either from cmdline or from boot properties
*/
-static char *
+static const char *
get_mode_value(char *name)
{
/*
* when specified on boot line it looks like "name" "="....
*/
if (boot_line != NULL) {
- return (find_boot_line_prop(name));
+ return (find_boot_prop(name));
}
#if defined(_BOOT)
@@ -377,8 +442,8 @@ static void
serial_adjust_prop(void)
{
char propname[20];
- char *propval;
- char *p;
+ const char *propval;
+ const char *p;
ulong_t baud;
uchar_t lcr = 0;
uchar_t mcr = DTR | RTS;
@@ -522,27 +587,47 @@ console_value_t console_devices[] = {
{ NULL, CONS_INVALID }
};
+static void
+bcons_init_env(struct xboot_info *xbi)
+{
+ uint32_t i;
+ struct boot_modules *modules;
+
+ modules = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
+ for (i = 0; i < xbi->bi_module_cnt; i++) {
+ if (modules[i].bm_type == BMT_ENV)
+ break;
+ }
+ if (i == xbi->bi_module_cnt)
+ return;
+
+ boot_env.be_env = (char *)(uintptr_t)modules[i].bm_addr;
+ boot_env.be_size = modules[i].bm_size;
+}
+
void
-bcons_init(char *bootstr)
+bcons_init(struct xboot_info *xbi)
{
console_value_t *consolep;
size_t len, cons_len;
- char *cons_str;
+ const char *cons_str;
#if !defined(_BOOT)
static char console_text[] = "text";
extern int post_fastreboot;
#endif
- boot_line = bootstr;
+ /* Set up data to fetch properties from commad line and boot env. */
+ boot_line = (char *)(uintptr_t)xbi->bi_cmdline;
+ bcons_init_env(xbi);
console = CONS_INVALID;
#if defined(__xpv)
- bcons_init_xen(bootstr);
+ bcons_init_xen(boot_line);
#endif /* __xpv */
- cons_str = find_boot_line_prop("console");
+ cons_str = find_boot_prop("console");
if (cons_str == NULL)
- cons_str = find_boot_line_prop("output-device");
+ cons_str = find_boot_prop("output-device");
#if !defined(_BOOT)
if (post_fastreboot && strcmp(cons_str, "graphics") == 0)
@@ -657,7 +742,6 @@ bcons_init(char *bootstr)
kb_init();
break;
}
- boot_line = NULL;
}
#if !defined(_BOOT)
diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c
index d7a9026bd5..d835f2b311 100644
--- a/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c
@@ -963,13 +963,11 @@ init_mem_alloc(void)
#else /* !__xpv */
-/* Stub in this version. */
static void
dboot_multiboot1_xboot_consinfo(void)
{
}
-/* Stub in this version. */
static void
dboot_multiboot2_xboot_consinfo(void)
{
@@ -1048,6 +1046,45 @@ dboot_multiboot_modcmdline(int index)
return (0);
}
+/*
+ * Find the environment module for console setup.
+ * Since we need the console to print early boot messages, the console is set up
+ * before anything else and therefore we need to pick up the environment module
+ * early too.
+ *
+ * Note, we just will search for and if found, will pass the env
+ * module to console setup, the proper module list processing will happen later.
+ */
+static void
+dboot_find_env(void)
+{
+ int i, modcount;
+ uint32_t mod_start, mod_end;
+ char *cmdline;
+
+ modcount = dboot_multiboot_modcount();
+
+ for (i = 0; i < modcount; ++i) {
+ cmdline = dboot_multiboot_modcmdline(i);
+ if (cmdline == NULL)
+ continue;
+
+ if (strstr(cmdline, "type=environment") == NULL)
+ continue;
+
+ mod_start = dboot_multiboot_modstart(i);
+ mod_end = dboot_multiboot_modend(i);
+ modules[0].bm_addr = mod_start;
+ modules[0].bm_size = mod_end - mod_start;
+ modules[0].bm_name = NULL;
+ modules[0].bm_hash = NULL;
+ modules[0].bm_type = BMT_ENV;
+ bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
+ bi->bi_module_cnt = 1;
+ return;
+ }
+}
+
static boolean_t
dboot_multiboot_basicmeminfo(uint32_t *lower, uint32_t *upper)
{
@@ -1144,6 +1181,8 @@ type_to_str(boot_module_type_t type)
return ("file");
case BMT_HASH:
return ("hash");
+ case BMT_ENV:
+ return ("environment");
default:
return ("unknown");
}
@@ -1262,6 +1301,8 @@ process_module(int midx)
modules[midx].bm_type = BMT_ROOTFS;
} else if (strcmp(q, "hash") == 0) {
modules[midx].bm_type = BMT_HASH;
+ } else if (strcmp(q, "environment") == 0) {
+ modules[midx].bm_type = BMT_ENV;
} else if (strcmp(q, "file") != 0) {
dboot_printf("\tmodule #%d: unknown module "
"type '%s'; defaulting to 'file'",
@@ -1789,6 +1830,11 @@ dboot_init_xboot_consinfo(void)
multiboot_version);
break;
}
+ /*
+ * Lookup environment module for the console. Complete module list
+ * will be built after console setup.
+ */
+ dboot_find_env();
#endif
}
@@ -1919,9 +1965,6 @@ startup_kernel(void)
bootloader = dboot_loader_name();
cmdline = dboot_loader_cmdline();
- prom_debug = (strstr(cmdline, "prom_debug") != NULL);
- map_debug = (strstr(cmdline, "map_debug") != NULL);
-
#if defined(__xpv)
/*
* For dom0, before we initialize the console subsystem we'll
@@ -1935,11 +1978,14 @@ startup_kernel(void)
dboot_init_xboot_consinfo();
bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
+ bcons_init(bi);
+
+ prom_debug = (find_boot_prop("prom_debug") != NULL);
+ map_debug = (find_boot_prop("map_debug") != NULL);
#if !defined(__xpv)
dboot_multiboot_get_fwtables();
#endif
- bcons_init(cmdline);
DBG_MSG("\n\nillumos prekernel set: ");
DBG_MSG(cmdline);
DBG_MSG("\n");
diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c
index b2a500ed9a..8616ef9f40 100644
--- a/usr/src/uts/i86pc/os/fakebop.c
+++ b/usr/src/uts/i86pc/os/fakebop.c
@@ -793,7 +793,7 @@ done:
bcons_init2(inputdev, outputdev, consoledev);
}
- if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug)
+ if (find_boot_prop("prom_debug") || kbm_debug)
boot_prop_display(line);
}
@@ -1202,6 +1202,125 @@ save_boot_info(struct xboot_info *xbi)
}
#endif /* __xpv */
+/*
+ * Import boot environment module variables as properties, applying
+ * blacklist filter for variables we know we will not use.
+ *
+ * Since the environment can be relatively large, containing many variables
+ * used only for boot loader purposes, we will use a blacklist based filter.
+ * To keep the blacklist from growing too large, we use prefix based filtering.
+ * This is possible because in many cases, the loader variable names are
+ * using a structured layout.
+ *
+ * We will not overwrite already set properties.
+ */
+static struct bop_blacklist {
+ const char *bl_name;
+ int bl_name_len;
+} bop_prop_blacklist[] = {
+ { "ISADIR", sizeof ("ISADIR") },
+ { "acpi", sizeof ("acpi") },
+ { "autoboot_delay", sizeof ("autoboot_delay") },
+ { "autoboot_delay", sizeof ("autoboot_delay") },
+ { "beansi_", sizeof ("beansi_") },
+ { "beastie", sizeof ("beastie") },
+ { "bemenu", sizeof ("bemenu") },
+ { "boot.", sizeof ("boot.") },
+ { "bootenv", sizeof ("bootenv") },
+ { "currdev", sizeof ("currdev") },
+ { "dhcp.", sizeof ("dhcp.") },
+ { "interpret", sizeof ("interpret") },
+ { "kernel", sizeof ("kernel") },
+ { "loaddev", sizeof ("loaddev") },
+ { "loader_", sizeof ("loader_") },
+ { "module_path", sizeof ("module_path") },
+ { "nfs.", sizeof ("nfs.") },
+ { "pcibios", sizeof ("pcibios") },
+ { "prompt", sizeof ("prompt") },
+ { "smbios", sizeof ("smbios") },
+ { "tem", sizeof ("tem") },
+ { "twiddle_divisor", sizeof ("twiddle_divisor") },
+ { "zfs_be", sizeof ("zfs_be") },
+};
+
+/*
+ * Match the name against prefixes in above blacklist. If the match was
+ * found, this name is blacklisted.
+ */
+static boolean_t
+name_is_blacklisted(const char *name)
+{
+ int i, n;
+
+ n = sizeof (bop_prop_blacklist) / sizeof (bop_prop_blacklist[0]);
+ for (i = 0; i < n; i++) {
+ if (strncmp(bop_prop_blacklist[i].bl_name, name,
+ bop_prop_blacklist[i].bl_name_len - 1) == 0) {
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+static void
+process_boot_environment(struct boot_modules *benv)
+{
+ char *env, *ptr, *name, *value;
+ uint32_t size, name_len, value_len;
+
+ if (benv == NULL || benv->bm_type != BMT_ENV)
+ return;
+ ptr = env = benv->bm_addr;
+ size = benv->bm_size;
+ do {
+ name = ptr;
+ /* find '=' */
+ while (*ptr != '=') {
+ ptr++;
+ if (ptr > env + size) /* Something is very wrong. */
+ return;
+ }
+ name_len = ptr - name;
+ if (sizeof (buffer) <= name_len)
+ continue;
+
+ (void) strncpy(buffer, name, sizeof (buffer));
+ buffer[name_len] = '\0';
+ name = buffer;
+
+ value_len = 0;
+ value = ++ptr;
+ while ((uintptr_t)ptr - (uintptr_t)env < size) {
+ if (*ptr == '\0') {
+ ptr++;
+ value_len = (uintptr_t)ptr - (uintptr_t)env;
+ break;
+ }
+ ptr++;
+ }
+
+ /* Did we reach the end of the module? */
+ if (value_len == 0)
+ return;
+
+ if (*value == '\0')
+ continue;
+
+ /* Is this property already set? */
+ if (do_bsys_getproplen(NULL, name) >= 0)
+ continue;
+
+ if (name_is_blacklisted(name) == B_TRUE)
+ continue;
+
+ /* Create new property. */
+ bsetprops(name, value);
+
+ /* Avoid reading past the module end. */
+ if (size <= (uintptr_t)ptr - (uintptr_t)env)
+ return;
+ } while (*ptr != '\0');
+}
/*
* 1st pass at building the table of boot properties. This includes:
@@ -1221,7 +1340,7 @@ build_boot_properties(struct xboot_info *xbp)
int name_len;
char *value;
int value_len;
- struct boot_modules *bm, *rdbm;
+ struct boot_modules *bm, *rdbm, *benv = NULL;
char *propbuf;
int quoted = 0;
int boot_arg_len;
@@ -1250,6 +1369,13 @@ build_boot_properties(struct xboot_info *xbp)
if (bm[i].bm_type == BMT_HASH || bm[i].bm_name == NULL)
continue;
+ if (bm[i].bm_type == BMT_ENV) {
+ if (benv == NULL)
+ benv = &bm[i];
+ else
+ continue;
+ }
+
(void) snprintf(modid, sizeof (modid),
"module-name-%u", midx);
bsetprops(modid, (char *)bm[i].bm_name);
@@ -1483,6 +1609,8 @@ build_boot_properties(struct xboot_info *xbp)
bsetprops("boot-args", boot_args);
bsetprops("bootargs", boot_args);
+ process_boot_environment(benv);
+
#ifndef __xpv
/*
* Build boot command line for Fast Reboot
@@ -1858,13 +1986,13 @@ _start(struct xboot_info *xbp)
}
#endif
- bcons_init((void *)xbp->bi_cmdline);
+ bcons_init(xbp);
have_console = 1;
/*
* enable debugging
*/
- if (strstr((char *)xbp->bi_cmdline, "kbm_debug"))
+ if (find_boot_prop("kbm_debug") != NULL)
kbm_debug = 1;
DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
@@ -1943,7 +2071,7 @@ _start(struct xboot_info *xbp)
DBG_MSG("Initializing boot properties:\n");
build_boot_properties(xbp);
- if (strstr((char *)xbp->bi_cmdline, "prom_debug") || kbm_debug) {
+ if (find_boot_prop("prom_debug") || kbm_debug) {
char *value;
value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
diff --git a/usr/src/uts/i86pc/sys/boot_console.h b/usr/src/uts/i86pc/sys/boot_console.h
index b2fcf98f97..187733615c 100644
--- a/usr/src/uts/i86pc/sys/boot_console.h
+++ b/usr/src/uts/i86pc/sys/boot_console.h
@@ -36,6 +36,8 @@
extern "C" {
#endif
+#include <sys/bootinfo.h>
+
#define CONS_INVALID -1
#define CONS_SCREEN_TEXT 0
#define CONS_TTY 1
@@ -53,9 +55,12 @@ extern void kb_init(void);
extern int kb_getchar(void);
extern int kb_ischar(void);
+/* Read property from command line or environment. */
+extern const char *find_boot_prop(const char *);
+
extern int boot_console_type(int *);
-extern void bcons_init(char *);
+extern void bcons_init(struct xboot_info *);
extern void bcons_putchar(int);
extern int bcons_getchar(void);
extern int bcons_ischar(void);
diff --git a/usr/src/uts/intel/sys/bootinfo.h b/usr/src/uts/intel/sys/bootinfo.h
index 9e205e342f..fa60e6ac41 100644
--- a/usr/src/uts/intel/sys/bootinfo.h
+++ b/usr/src/uts/intel/sys/bootinfo.h
@@ -61,7 +61,8 @@ typedef void *native_ptr_t;
typedef enum boot_module_type {
BMT_ROOTFS,
BMT_FILE,
- BMT_HASH
+ BMT_HASH,
+ BMT_ENV
} boot_module_type_t;
struct boot_memlist {