From f289ce6eb03db0584699ec4fed88ef795a33dd79 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 21 Jan 2017 16:45:38 +0200 Subject: [PATCH] 7839 uts: implement boot environment support Reviewed by: Robert Mustacchi Reviewed by: Hans Rosenfeld Approved by: Joshua M. Clulow --- usr/src/uts/i86pc/boot/boot_console.c | 130 +++++++++++++++++++++++----- usr/src/uts/i86pc/dboot/dboot_startkern.c | 58 +++++++++++-- usr/src/uts/i86pc/os/fakebop.c | 138 ++++++++++++++++++++++++++++-- usr/src/uts/i86pc/sys/boot_console.h | 7 +- usr/src/uts/intel/sys/bootinfo.h | 3 +- 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 + #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 { -- 2.11.4.GIT