diff options
Diffstat (limited to 'common/bootm.c')
| -rw-r--r-- | common/bootm.c | 172 | 
1 files changed, 141 insertions, 31 deletions
| diff --git a/common/bootm.c b/common/bootm.c index 167eea4a1e9..8298693900d 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -7,6 +7,7 @@  #ifndef USE_HOSTCC  #include <common.h>  #include <bootstage.h> +#include <cli.h>  #include <cpu_func.h>  #include <env.h>  #include <errno.h> @@ -19,6 +20,7 @@  #include <net.h>  #include <asm/cache.h>  #include <asm/io.h> +#include <linux/sizes.h>  #if defined(CONFIG_CMD_USB)  #include <usb.h>  #endif @@ -35,6 +37,8 @@  #define CONFIG_SYS_BOOTM_LEN	0x800000  #endif +#define MAX_CMDLINE_SIZE	SZ_4K +  #define IH_INITRD_ARCH IH_ARCH_DEFAULT  #ifndef USE_HOSTCC @@ -465,19 +469,35 @@ ulong bootm_disable_interrupts(void)  	return iflag;  } -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) - -#define CONSOLE_ARG     "console=" -#define CONSOLE_ARG_LEN (sizeof(CONSOLE_ARG) - 1) +#define CONSOLE_ARG		"console=" +#define CONSOLE_ARG_SIZE	sizeof(CONSOLE_ARG) -static void fixup_silent_linux(void) +/** + * fixup_silent_linux() - Handle silencing the linux boot if required + * + * This uses the silent_linux envvar to control whether to add/set a "console=" + * parameter to the command line + * + * @buf: Buffer containing the string to process + * @maxlen: Maximum length of buffer + * @return 0 if OK, -ENOSPC if @maxlen is too small + */ +static int fixup_silent_linux(char *buf, int maxlen)  { -	char *buf; -	const char *env_val; -	char *cmdline = env_get("bootargs");  	int want_silent; +	char *cmdline; +	int size;  	/* +	 * Move the input string to the end of buffer. The output string will be +	 * built up at the start. +	 */ +	size = strlen(buf) + 1; +	if (size * 2 > maxlen) +		return -ENOSPC; +	cmdline = buf + maxlen - size; +	memmove(cmdline, buf, size); +	/*  	 * Only fix cmdline when requested. The environment variable can be:  	 *  	 *	no - we never fixup @@ -486,44 +506,132 @@ static void fixup_silent_linux(void)  	 */  	want_silent = env_get_yesno("silent_linux");  	if (want_silent == 0) -		return; +		return 0;  	else if (want_silent == -1 && !(gd->flags & GD_FLG_SILENT)) -		return; +		return 0;  	debug("before silent fix-up: %s\n", cmdline); -	if (cmdline && (cmdline[0] != '\0')) { +	if (*cmdline) {  		char *start = strstr(cmdline, CONSOLE_ARG); -		/* Allocate space for maximum possible new command line */ -		buf = malloc(strlen(cmdline) + 1 + CONSOLE_ARG_LEN + 1); -		if (!buf) { -			debug("%s: out of memory\n", __func__); -			return; -		} +		/* Check space for maximum possible new command line */ +		if (size + CONSOLE_ARG_SIZE > maxlen) +			return -ENOSPC;  		if (start) {  			char *end = strchr(start, ' '); -			int num_start_bytes = start - cmdline + CONSOLE_ARG_LEN; +			int start_bytes; -			strncpy(buf, cmdline, num_start_bytes); +			start_bytes = start - cmdline + CONSOLE_ARG_SIZE - 1; +			strncpy(buf, cmdline, start_bytes);  			if (end) -				strcpy(buf + num_start_bytes, end); +				strcpy(buf + start_bytes, end);  			else -				buf[num_start_bytes] = '\0'; +				buf[start_bytes] = '\0';  		} else {  			sprintf(buf, "%s %s", cmdline, CONSOLE_ARG);  		} -		env_val = buf; +		if (buf + strlen(buf) >= cmdline) +			return -ENOSPC;  	} else { -		buf = NULL; -		env_val = CONSOLE_ARG; +		if (maxlen < sizeof(CONSOLE_ARG)) +			return -ENOSPC; +		strcpy(buf, CONSOLE_ARG);  	} +	debug("after silent fix-up: %s\n", buf); + +	return 0; +} -	env_set("bootargs", env_val); -	debug("after silent fix-up: %s\n", env_val); +/** + * process_subst() - Handle substitution of ${...} fields in the environment + * + * Handle variable substitution in the provided buffer + * + * @buf: Buffer containing the string to process + * @maxlen: Maximum length of buffer + * @return 0 if OK, -ENOSPC if @maxlen is too small + */ +static int process_subst(char *buf, int maxlen) +{ +	char *cmdline; +	int size; +	int ret; + +	/* Move to end of buffer */ +	size = strlen(buf) + 1; +	cmdline = buf + maxlen - size; +	if (buf + size > cmdline) +		return -ENOSPC; +	memmove(cmdline, buf, size); + +	ret = cli_simple_process_macros(cmdline, buf, cmdline - buf); + +	return ret; +} + +int bootm_process_cmdline(char *buf, int maxlen, int flags) +{ +	int ret; + +	/* Check config first to enable compiler to eliminate code */ +	if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && +	    !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && +	    (flags & BOOTM_CL_SILENT)) { +		ret = fixup_silent_linux(buf, maxlen); +		if (ret) +			return log_msg_ret("silent", ret); +	} +	if (IS_ENABLED(CONFIG_BOOTARGS_SUBST) && (flags & BOOTM_CL_SUBST)) { +		ret = process_subst(buf, maxlen); +		if (ret) +			return log_msg_ret("silent", ret); +	} + +	return 0; +} + +int bootm_process_cmdline_env(int flags) +{ +	const int maxlen = MAX_CMDLINE_SIZE; +	bool do_silent; +	const char *env; +	char *buf; +	int ret; + +	/* First check if any action is needed */ +	do_silent = IS_ENABLED(CONFIG_SILENT_CONSOLE) && +	    !IS_ENABLED(CONFIG_SILENT_U_BOOT_ONLY) && (flags & BOOTM_CL_SILENT); +	if (!do_silent && !IS_ENABLED(CONFIG_BOOTARGS_SUBST)) +		return 0; + +	env = env_get("bootargs"); +	if (env && strlen(env) >= maxlen) +		return -E2BIG; +	buf = malloc(maxlen); +	if (!buf) +		return -ENOMEM; +	if (env) +		strcpy(buf, env); +	else +		*buf = '\0'; +	ret = bootm_process_cmdline(buf, maxlen, flags); +	if (!ret) { +		ret = env_set("bootargs", buf); + +		/* +		 * If buf is "" and bootargs does not exist, this will produce +		 * an error trying to delete bootargs. Ignore it +		 */ +		if (ret == -ENOENT) +			ret = 0; +	}  	free(buf); +	if (ret) +		return log_msg_ret("env", ret); + +	return 0;  } -#endif /* CONFIG_SILENT_CONSOLE */  /**   * Execute selected states of the bootm command. @@ -627,10 +735,12 @@ int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,  	if (!ret && (states & BOOTM_STATE_OS_BD_T))  		ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);  	if (!ret && (states & BOOTM_STATE_OS_PREP)) { -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) -		if (images->os.os == IH_OS_LINUX) -			fixup_silent_linux(); -#endif +		ret = bootm_process_cmdline_env(images->os.os == IH_OS_LINUX); +		if (ret) { +			printf("Cmdline setup failed (err=%d)\n", ret); +			ret = CMD_RET_FAILURE; +			goto err; +		}  		ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);  	} | 
