diff options
Diffstat (limited to 'common')
42 files changed, 3330 insertions, 427 deletions
| diff --git a/common/Makefile b/common/Makefile index ded6318dc..54fcc8158 100644 --- a/common/Makefile +++ b/common/Makefile @@ -30,6 +30,7 @@ ifndef CONFIG_SPL_BUILD  COBJS-y += main.o  COBJS-y += command.o  COBJS-y += exports.o +COBJS-y += hash.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o  COBJS-y += s_record.o  COBJS-y += xyzModem.o @@ -43,7 +44,10 @@ COBJS-y += cmd_nvedit.o  COBJS-y += cmd_version.o  # environment +COBJS-y += env_attr.o +COBJS-y += env_callback.o  COBJS-y += env_common.o +COBJS-y += env_flags.o  COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o  COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o  XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o @@ -101,8 +105,10 @@ ifdef CONFIG_FPGA  COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o  endif  COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o +COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o  COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o  COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o +COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o  COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o  COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o  COBJS-$(CONFIG_CMD_INI) += cmd_ini.o @@ -118,6 +124,7 @@ COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o  COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o  COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o  COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o +COBJS-$(CONFIG_CMD_IO) += cmd_io.o  COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o  COBJS-$(CONFIG_MII) += miiphyutil.o  COBJS-$(CONFIG_CMD_MII) += miiphyutil.o @@ -142,6 +149,7 @@ endif  COBJS-y += cmd_pcmcia.o  COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o  COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o +COBJS-$(CONFIG_CMD_READ) += cmd_read.o  COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o  COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o  COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o @@ -185,6 +193,7 @@ COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o  COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o  COBJS-y += flash.o  COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o +COBJS-$(CONFIG_I2C_EDID) += edid.o  COBJS-$(CONFIG_KALLSYMS) += kallsyms.o  COBJS-$(CONFIG_LCD) += lcd.o  COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o @@ -193,12 +202,19 @@ COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o  COBJS-$(CONFIG_UPDATE_TFTP) += update.o  COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o  COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o +COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o  endif  ifdef CONFIG_SPL_BUILD +COBJS-y += cmd_nvedit.o +COBJS-y += env_common.o +COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o  COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o  COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o  endif diff --git a/common/bouncebuf.c b/common/bouncebuf.c index 4f827f893..1df12cdda 100644 --- a/common/bouncebuf.c +++ b/common/bouncebuf.c @@ -27,21 +27,19 @@  #include <errno.h>  #include <bouncebuf.h> -static int addr_aligned(void *data, size_t len) +static int addr_aligned(struct bounce_buffer *state)  {  	const ulong align_mask = ARCH_DMA_MINALIGN - 1;  	/* Check if start is aligned */ -	if ((ulong)data & align_mask) { -		debug("Unaligned start address %p\n", data); +	if ((ulong)state->user_buffer & align_mask) { +		debug("Unaligned buffer address %p\n", state->user_buffer);  		return 0;  	} -	data += len; - -	/* Check if end is aligned */ -	if ((ulong)data & align_mask) { -		debug("Unaligned end address %p\n", data); +	/* Check if length is aligned */ +	if (state->len != state->len_aligned) { +		debug("Unaligned buffer length %d\n", state->len);  		return 0;  	} @@ -49,44 +47,53 @@ static int addr_aligned(void *data, size_t len)  	return 1;  } -int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags) +int bounce_buffer_start(struct bounce_buffer *state, void *data, +			size_t len, unsigned int flags)  { -	void *tmp; -	size_t alen; - -	if (addr_aligned(*data, len)) { -		*backup = NULL; -		return 0; -	} +	state->user_buffer = data; +	state->bounce_buffer = data; +	state->len = len; +	state->len_aligned = roundup(len, ARCH_DMA_MINALIGN); +	state->flags = flags; -	alen = roundup(len, ARCH_DMA_MINALIGN); -	tmp = memalign(ARCH_DMA_MINALIGN, alen); +	if (!addr_aligned(state)) { +		state->bounce_buffer = memalign(ARCH_DMA_MINALIGN, +						state->len_aligned); +		if (!state->bounce_buffer) +			return -ENOMEM; -	if (!tmp) -		return -ENOMEM; - -	if (flags & GEN_BB_READ) -		memcpy(tmp, *data, len); +		if (state->flags & GEN_BB_READ) +			memcpy(state->bounce_buffer, state->user_buffer, +				state->len); +	} -	*backup = *data; -	*data = tmp; +	/* +	 * Flush data to RAM so DMA reads can pick it up, +	 * and any CPU writebacks don't race with DMA writes +	 */ +	flush_dcache_range((unsigned long)state->bounce_buffer, +				(unsigned long)(state->bounce_buffer) + +					state->len_aligned);  	return 0;  } -int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags) +int bounce_buffer_stop(struct bounce_buffer *state)  { -	void *tmp = *data; +	if (state->flags & GEN_BB_WRITE) { +		/* Invalidate cache so that CPU can see any newly DMA'd data */ +		invalidate_dcache_range((unsigned long)state->bounce_buffer, +					(unsigned long)(state->bounce_buffer) + +						state->len_aligned); +	} -	/* The buffer was already aligned, since "backup" is NULL. */ -	if (!*backup) +	if (state->bounce_buffer == state->user_buffer)  		return 0; -	if (flags & GEN_BB_WRITE) -		memcpy(*backup, *data, len); +	if (state->flags & GEN_BB_WRITE) +		memcpy(state->user_buffer, state->bounce_buffer, state->len); -	*data = *backup; -	free(tmp); +	free(state->bounce_buffer);  	return 0;  } diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c index b8809e3bf..5a52edde3 100644 --- a/common/cmd_bmp.c +++ b/common/cmd_bmp.c @@ -31,6 +31,7 @@  #include <command.h>  #include <asm/byteorder.h>  #include <malloc.h> +#include <video.h>  static int bmp_info (ulong addr); @@ -238,9 +239,7 @@ int bmp_display(ulong addr, int x, int y)  #if defined(CONFIG_LCD)  	ret = lcd_display_bitmap((ulong)bmp, x, y);  #elif defined(CONFIG_VIDEO) -	extern int video_display_bitmap (ulong, int, int); - -	ret = video_display_bitmap ((unsigned long)bmp, x, y); +	ret = video_display_bitmap((unsigned long)bmp, x, y);  #else  # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO  #endif diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index d256ddfaa..f7595c031 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -537,7 +537,7 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,  		}  			break;  #endif -#if defined(CONFIG_OF_LIBFDT) +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)  		case BOOTM_STATE_FDT:  		{  			boot_fdt_add_mem_rsv_regions(&images.lmb, @@ -949,8 +949,19 @@ static void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,  			 * node  			 */  			bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); +#ifdef CONFIG_FIT_BEST_MATCH +			if (fit_uname_config) +				cfg_noffset = +					fit_conf_get_node(fit_hdr, +							  fit_uname_config); +			else +				cfg_noffset = +					fit_conf_find_compat(fit_hdr, +							     gd->fdt_blob); +#else  			cfg_noffset = fit_conf_get_node(fit_hdr,  							fit_uname_config); +#endif  			if (cfg_noffset < 0) {  				bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME);  				return NULL; diff --git a/common/cmd_gettime.c b/common/cmd_gettime.c new file mode 100644 index 000000000..d7d36a987 --- /dev/null +++ b/common/cmd_gettime.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec + */ +#include <common.h> +#include <command.h> + +static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc, +		      char * const argv[]) +{ +	unsigned long int val = get_timer(0); + +#ifdef CONFIG_SYS_HZ +	printf("Timer val: %lu\n", val); +	printf("Seconds : %lu\n", val / CONFIG_SYS_HZ); +	printf("Remainder : %lu\n", val % CONFIG_SYS_HZ); +	printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ); +#else +	printf("CONFIG_SYS_HZ not defined"); +	printf("Timer Val %lu", val); +#endif + +	return 0; +} + +U_BOOT_CMD( +	gettime,	1,	1,	do_gettime, +	"get timer val elapsed,\n", +	"get time elapsed from uboot start\n" +); diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c new file mode 100644 index 000000000..da7705da6 --- /dev/null +++ b/common/cmd_gpt.c @@ -0,0 +1,333 @@ +/* + * cmd_gpt.c -- GPT (GUID Partition Table) handling command + * + * Copyright (C) 2012 Samsung Electronics + * author: Lukasz Majewski <l.majewski@samsung.com> + * author: Piotr Wilczek <p.wilczek@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <common.h> +#include <malloc.h> +#include <command.h> +#include <mmc.h> +#include <part_efi.h> +#include <exports.h> +#include <linux/ctype.h> + +#ifndef CONFIG_PARTITION_UUIDS +#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled +#endif + +/** + * extract_env(): Expand env name from string format '&{env_name}' + *                and return pointer to the env (if the env is set) + * + * @param str - pointer to string + * @param env - pointer to pointer to extracted env + * + * @return - zero on successful expand and env is set + */ +static char extract_env(const char *str, char **env) +{ +	char *e, *s; + +	if (!str || strlen(str) < 4) +		return -1; + +	if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) { +		s = strdup(str); +		if (s == NULL) +			return -1; +		memset(s + strlen(s) - 1, '\0', 1); +		memmove(s, s + 2, strlen(s) - 1); +		e = getenv(s); +		free(s); +		if (e == NULL) { +			printf("Environmental '%s' not set\n", str); +			return -1; /* env not set */ +		} +		*env = e; +		return 0; +	} + +	return -1; +} + +/** + * extract_val(): Extract value from a key=value pair list (comma separated). + *                Only value for the given key is returend. + *                Function allocates memory for the value, remember to free! + * + * @param str - pointer to string with key=values pairs + * @param key - pointer to the key to search for + * + * @return - pointer to allocated string with the value + */ +static char *extract_val(const char *str, const char *key) +{ +	char *v, *k; +	char *s, *strcopy; +	char *new = NULL; + +	strcopy = strdup(str); +	if (strcopy == NULL) +		return NULL; + +	s = strcopy; +	while (s) { +		v = strsep(&s, ","); +		if (!v) +			break; +		k = strsep(&v, "="); +		if (!k) +			break; +		if  (strcmp(k, key) == 0) { +			new = strdup(v); +			break; +		} +	} + +	free(strcopy); + +	return new; +} + +/** + * set_gpt_info(): Fill partition information from string + *		function allocates memory, remember to free! + * + * @param dev_desc - pointer block device descriptor + * @param str_part - pointer to string with partition information + * @param str_disk_guid - pointer to pointer to allocated string with disk guid + * @param partitions - pointer to pointer to allocated partitions array + * @param parts_count - number of partitions + * + * @return - zero on success, otherwise error + * + */ +static int set_gpt_info(block_dev_desc_t *dev_desc, +			const char *str_part, +			char **str_disk_guid, +			disk_partition_t **partitions, +			u8 *parts_count) +{ +	char *tok, *str, *s; +	int i; +	char *val, *p; +	int p_count; +	disk_partition_t *parts; +	int errno = 0; + +	debug("%s: MMC lba num: 0x%x %d\n", __func__, +	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); + +	if (str_part == NULL) +		return -1; + +	str = strdup(str_part); + +	/* extract disk guid */ +	s = str; +	tok = strsep(&s, ";"); +	val = extract_val(tok, "uuid_disk"); +	if (!val) { +		free(str); +		return -2; +	} +	if (extract_env(val, &p)) +		p = val; +	*str_disk_guid = strdup(p); +	free(val); + +	if (strlen(s) == 0) +		return -3; + +	i = strlen(s) - 1; +	if (s[i] == ';') +		s[i] = '\0'; + +	/* calculate expected number of partitions */ +	p_count = 1; +	p = s; +	while (*p) { +		if (*p++ == ';') +			p_count++; +	} + +	/* allocate memory for partitions */ +	parts = calloc(sizeof(disk_partition_t), p_count); + +	/* retrive partions data from string */ +	for (i = 0; i < p_count; i++) { +		tok = strsep(&s, ";"); + +		if (tok == NULL) +			break; + +		/* uuid */ +		val = extract_val(tok, "uuid"); +		if (!val) { /* 'uuid' is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		if (strlen(p) >= sizeof(parts[i].uuid)) { +			printf("Wrong uuid format for partition %d\n", i); +			errno = -4; +			goto err; +		} +		strcpy((char *)parts[i].uuid, p); +		free(val); + +		/* name */ +		val = extract_val(tok, "name"); +		if (!val) { /* name is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		if (strlen(p) >= sizeof(parts[i].name)) { +			errno = -4; +			goto err; +		} +		strcpy((char *)parts[i].name, p); +		free(val); + +		/* size */ +		val = extract_val(tok, "size"); +		if (!val) { /* 'size' is mandatory */ +			errno = -4; +			goto err; +		} +		if (extract_env(val, &p)) +			p = val; +		parts[i].size = ustrtoul(p, &p, 0); +		parts[i].size /= dev_desc->blksz; +		free(val); + +		/* start address */ +		val = extract_val(tok, "start"); +		if (val) { /* start address is optional */ +			if (extract_env(val, &p)) +				p = val; +			parts[i].start = ustrtoul(p, &p, 0); +			parts[i].start /= dev_desc->blksz; +			free(val); +		} +	} + +	*parts_count = p_count; +	*partitions = parts; +	free(str); + +	return 0; +err: +	free(str); +	free(*str_disk_guid); +	free(parts); + +	return errno; +} + +static int gpt_mmc_default(int dev, const char *str_part) +{ +	int ret; +	char *str_disk_guid; +	u8 part_count = 0; +	disk_partition_t *partitions = NULL; + +	struct mmc *mmc = find_mmc_device(dev); + +	if (mmc == NULL) { +		printf("%s: mmc dev %d NOT available\n", __func__, dev); +		return CMD_RET_FAILURE; +	} + +	if (!str_part) +		return -1; + +	/* fill partitions */ +	ret = set_gpt_info(&mmc->block_dev, str_part, +			&str_disk_guid, &partitions, &part_count); +	if (ret) { +		if (ret == -1) +			printf("No partition list provided\n"); +		if (ret == -2) +			printf("Missing disk guid\n"); +		if ((ret == -3) || (ret == -4)) +			printf("Partition list incomplete\n"); +		return -1; +	} + +	/* save partitions layout to disk */ +	gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count); +	free(str_disk_guid); +	free(partitions); + +	return 0; +} + +/** + * do_gpt(): Perform GPT operations + * + * @param cmdtp - command name + * @param flag + * @param argc + * @param argv + * + * @return zero on success; otherwise error + */ +static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	int ret = CMD_RET_SUCCESS; +	int dev = 0; +	char *pstr; + +	if (argc < 5) +		return CMD_RET_USAGE; + +	/* command: 'write' */ +	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { +		/* device: 'mmc' */ +		if (strcmp(argv[2], "mmc") == 0) { +			/* check if 'dev' is a number */ +			for (pstr = argv[3]; *pstr != '\0'; pstr++) +				if (!isdigit(*pstr)) { +					printf("'%s' is not a number\n", +						argv[3]); +					return CMD_RET_USAGE; +				} +			dev = (int)simple_strtoul(argv[3], NULL, 10); +			/* write to mmc */ +			if (gpt_mmc_default(dev, argv[4])) +				return CMD_RET_FAILURE; +		} +	} else { +		return CMD_RET_USAGE; +	} +	return ret; +} + +U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, +	"GUID Partition Table", +	"<command> <interface> <dev> <partions_list>\n" +	" - GUID partition table restoration\n" +	" Restore GPT information on a device connected\n" +	" to interface\n" +); diff --git a/common/cmd_hash.c b/common/cmd_hash.c new file mode 100644 index 000000000..689c60857 --- /dev/null +++ b/common/cmd_hash.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <hash.h> + +static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +#ifdef CONFIG_HASH_VERIFY +	int verify = 0; + +	if (!strcmp(argv[1], "-v")) { +		verify = 1; +		argc--; +		argv++; +	} +#endif +	/* Move forward to 'algorithm' parameter */ +	argc--; +	argv++; +	return hash_command(*argv, verify, cmdtp, flag, argc - 1, argv + 1); +} + +#ifdef CONFIG_HASH_VERIFY +U_BOOT_CMD( +	hash,	6,	1,	do_hash, +	"compute hash message digest", +	"algorithm address count [[*]sum_dest]\n" +		"    - compute message digest [save to env var / *address]\n" +	"hash -v algorithm address count [*]sum\n" +		"    - verify hash of memory area with env var / *address" +); +#else +U_BOOT_CMD( +	hash,	5,	1,	do_hash, +	"compute message digest", +	"algorithm address count [[*]sum_dest]\n" +		"    - compute message digest [save to env var / *address]" +); +#endif diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 4438db594..438079447 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -78,10 +78,12 @@  #include <common.h>  #include <command.h> +#include <edid.h>  #include <environment.h>  #include <i2c.h>  #include <malloc.h>  #include <asm/byteorder.h> +#include <linux/compiler.h>  /* Display values from last command.   * Memory modify remembered values are different from display memory. @@ -132,35 +134,65 @@ DECLARE_GLOBAL_DATA_PTR;  #define DISP_LINE_LEN	16 -/* implement possible board specific board init */ -static void __def_i2c_init_board(void) +/** + * i2c_init_board() - Board-specific I2C bus init + * + * This function is the default no-op implementation of I2C bus + * initialization. This function can be overriden by board-specific + * implementation if needed. + */ +__weak +void i2c_init_board(void)  {  	return;  } -void i2c_init_board(void) -	__attribute__((weak, alias("__def_i2c_init_board")));  /* TODO: Implement architecture-specific get/set functions */ -static unsigned int __def_i2c_get_bus_speed(void) + +/** + * i2c_get_bus_speed() - Return I2C bus speed + * + * This function is the default implementation of function for retrieveing + * the current I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns I2C bus speed in Hz. + */ +__weak +unsigned int i2c_get_bus_speed(void)  {  	return CONFIG_SYS_I2C_SPEED;  } -unsigned int i2c_get_bus_speed(void) -	__attribute__((weak, alias("__def_i2c_get_bus_speed"))); -static int __def_i2c_set_bus_speed(unsigned int speed) +/** + * i2c_set_bus_speed() - Configure I2C bus speed + * @speed:	Newly set speed of the I2C bus in Hz + * + * This function is the default implementation of function for setting + * the I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns zero on success, negative value on error. + */ +__weak +int i2c_set_bus_speed(unsigned int speed)  {  	if (speed != CONFIG_SYS_I2C_SPEED)  		return -1;  	return 0;  } -int i2c_set_bus_speed(unsigned int) -	__attribute__((weak, alias("__def_i2c_set_bus_speed"))); -/* - * get_alen: small parser helper function to get address length - * returns the address length +/** + * get_alen() - Small parser helper function to get address length + * + * Returns the address length.   */  static uint get_alen(char *arg)  { @@ -178,11 +210,19 @@ static uint get_alen(char *arg)  	return alen;  } -/* +/** + * do_i2c_read() - Handle the "i2c read" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr}   */ -  static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	u_char	chip; @@ -271,7 +311,16 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[  	return 0;  } -/* +/** + * do_i2c_md() - Handle the "i2c md" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c md {i2c_chip} {addr}{.0, .1, .2} {len}   */ @@ -363,8 +412,15 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  	return 0;  } - -/* Write (fill) memory +/** + * do_i2c_mw() - Handle the "i2c mw" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] @@ -421,10 +477,20 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  #endif  	} -	return (0); +	return 0;  } -/* Calculate a CRC on memory +/** + * do_i2c_crc() - Handle the "i2c crc32" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Calculate a CRC on memory + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count} @@ -481,13 +547,22 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  	return 0;  } -/* Modify memory. +/** + * mod_i2c_mem() - Handle the "i2c mm" and "i2c nm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Modify memory. + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error.   *   * Syntax:   *	i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}   *	i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}   */ -  static int  mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])  { @@ -603,7 +678,16 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg  	return 0;  } -/* +/** + * do_i2c_probe() - Handle the "i2c probe" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c probe {addr}   * @@ -657,7 +741,16 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv  	return (0 == found);  } -/* +/** + * do_i2c_loop() - Handle the "i2c loop" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + *   * Syntax:   *	i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}]   *	{length} - Number of bytes to read @@ -718,6 +811,8 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  /*   * The SDRAM command is separately configured because many   * (most?) embedded boards don't use SDRAM DIMMs. + * + * FIXME: Document and probably move elsewhere!   */  #if defined(CONFIG_CMD_SDRAM)  static void print_ddr2_tcyc (u_char const b) @@ -1246,7 +1341,48 @@ static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  }  #endif +/* + * Syntax: + *	i2c edid {i2c_chip} + */ +#if defined(CONFIG_I2C_EDID) +int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	u_char chip; +	struct edid1_info edid; + +	if (argc < 2) { +		cmd_usage(cmdtp); +		return 1; +	} + +	chip = simple_strtoul(argv[1], NULL, 16); +	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { +		puts("Error reading EDID content.\n"); +		return 1; +	} + +	if (edid_check_info(&edid)) { +		puts("Content isn't valid EDID.\n"); +		return 1; +	} + +	edid_print_info(&edid); +	return 0; + +} +#endif /* CONFIG_I2C_EDID */ +  #if defined(CONFIG_I2C_MUX) +/** + * do_i2c_add_bus() - Handle the "i2c bus" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero always. + */  static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int ret=0; @@ -1276,6 +1412,16 @@ static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar  #endif  /* CONFIG_I2C_MUX */  #if defined(CONFIG_I2C_MULTI_BUS) +/** + * do_i2c_bus_num() - Handle the "i2c dev" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int bus_idx, ret=0; @@ -1294,6 +1440,16 @@ static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar  }  #endif  /* CONFIG_I2C_MULTI_BUS */ +/** + * do_i2c_bus_speed() - Handle the "i2c speed" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	int speed, ret=0; @@ -1311,16 +1467,45 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const  	return ret;  } +/** + * do_i2c_mm() - Handle the "i2c mm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	return mod_i2c_mem (cmdtp, 1, flag, argc, argv);  } +/** + * do_i2c_nm() - Handle the "i2c nm" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	return mod_i2c_mem (cmdtp, 0, flag, argc, argv);  } +/** + * do_i2c_reset() - Handle the "i2c reset" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero always. + */  static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -1335,6 +1520,9 @@ static cmd_tbl_t cmd_i2c_sub[] = {  #if defined(CONFIG_I2C_MULTI_BUS)  	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),  #endif  /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) +	U_BOOT_CMD_MKENT(edid, 1, 1, do_edid, "", ""), +#endif  /* CONFIG_I2C_EDID */  	U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""),  	U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""),  	U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""), @@ -1356,6 +1544,16 @@ void i2c_reloc(void) {  }  #endif +/** + * do_i2c() - Handle the "i2c" command-line command + * @cmdtp:	Command data struct pointer + * @flag:	Command flag + * @argc:	Command-line argument count + * @argv:	Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */  static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  {  	cmd_tbl_t *c; @@ -1385,6 +1583,9 @@ static char i2c_help_text[] =  #if defined(CONFIG_I2C_MULTI_BUS)  	"i2c dev [dev] - show or set current I2C bus\n"  #endif  /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) +	"i2c edid chip - print EDID configuration information\n" +#endif  /* CONFIG_I2C_EDID */  	"i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n"  	"i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n"  	"i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n" diff --git a/common/cmd_io.c b/common/cmd_io.c new file mode 100644 index 000000000..6450cb576 --- /dev/null +++ b/common/cmd_io.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * IO space access commands. + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> + +/* + * IO Display + * + * Syntax: + *	iod{.b, .w, .l} {addr} + */ +int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	ulong addr; +	int size; + +	if (argc != 2) +		return CMD_RET_USAGE; + +	size = cmd_get_data_size(argv[0], 4); +	if (size < 0) +		return 1; + +	addr = simple_strtoul(argv[1], NULL, 16); + +	printf("%04x: ", (u16) addr); + +	if (size == 4) +		printf("%08x\n", inl(addr)); +	else if (size == 2) +		printf("%04x\n", inw(addr)); +	else +		printf("%02x\n", inb(addr)); + +	return 0; +} + +int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	ulong addr, size, val; + +	if (argc != 3) +		return CMD_RET_USAGE; + +	size = cmd_get_data_size(argv[0], 4); +	if (size < 0) +		return 1; + +	addr = simple_strtoul(argv[1], NULL, 16); +	val = simple_strtoul(argv[2], NULL, 16); + +	if (size == 4) +		outl((u32) val, addr); +	else if (size == 2) +		outw((u16) val, addr); +	else +		outb((u8) val, addr); + +	return 0; +} + +/**************************************************/ +U_BOOT_CMD(iod, 2, 0, do_io_iod, +	   "IO space display", "[.b, .w, .l] address [# of objects]"); + +U_BOOT_CMD(iow, 3, 0, do_io_iow, +	   "IO space modify (auto-incrementing address)", +	   "[.b, .w, .l] address"); diff --git a/common/cmd_led.c b/common/cmd_led.c index d83b3ba69..7f5ab43c7 100644 --- a/common/cmd_led.c +++ b/common/cmd_led.c @@ -140,7 +140,7 @@ int do_led (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  U_BOOT_CMD(  	led, 3, 1, do_led, -	"led\t- [" +	"["  #ifdef CONFIG_BOARD_SPECIFIC_LED  #ifdef STATUS_LED_BIT  	"0|" @@ -167,6 +167,6 @@ U_BOOT_CMD(  #ifdef STATUS_LED_BLUE  	"blue|"  #endif -	"all] [on|off|toggle]\n", -	"led [led_name] [on|off|toggle] sets or clears led(s)\n" +	"all] [on|off|toggle]", +	"[led_name] [on|off|toggle] sets or clears led(s)"  ); diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 62a1c224d..7dacd5114 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -144,7 +144,7 @@ static int do_mmcinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  U_BOOT_CMD(  	mmcinfo, 1, 0, do_mmcinfo,  	"display MMC info", -	"- dislay info of the current MMC device" +	"- display info of the current MMC device"  );  static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -250,14 +250,13 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		return 0;  	} -	if (strcmp(argv[1], "read") == 0) +	state = MMC_INVALID; +	if (argc == 5 && strcmp(argv[1], "read") == 0)  		state = MMC_READ; -	else if (strcmp(argv[1], "write") == 0) +	else if (argc == 5 && strcmp(argv[1], "write") == 0)  		state = MMC_WRITE; -	else if (strcmp(argv[1], "erase") == 0) +	else if (argc == 4 && strcmp(argv[1], "erase") == 0)  		state = MMC_ERASE; -	else -		state = MMC_INVALID;  	if (state != MMC_INVALID) {  		struct mmc *mmc = find_mmc_device(curr_device); diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 4b1606972..1568594ca 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -700,6 +700,25 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		return ret == 0 ? 0 : 1;  	} +#ifdef CONFIG_CMD_NAND_TORTURE +	if (strcmp(cmd, "torture") == 0) { +		if (argc < 3) +			goto usage; + +		if (!str2off(argv[2], &off)) { +			puts("Offset is not a valid number\n"); +			return 1; +		} + +		printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n", +			dev, off, nand->erasesize); +		ret = nand_torture(nand, off); +		printf(" %s\n", ret ? "Failed" : "Passed"); + +		return ret == 0 ? 0 : 1; +	} +#endif +  	if (strcmp(cmd, "markbad") == 0) {  		argc -= 2;  		argv += 2; @@ -810,6 +829,9 @@ static char nand_help_text[] =  	"nand erase.chip [clean] - erase entire chip'\n"  	"nand bad - show bad blocks\n"  	"nand dump[.oob] off - dump page\n" +#ifdef CONFIG_CMD_NAND_TORTURE +	"nand torture off - torture block at offset\n" +#endif  	"nand scrub [-y] off size | scrub.part partition | scrub.chip\n"  	"    really clean NAND erasing bad blocks (UNSAFE)\n"  	"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 006131f45..7633f0c44 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -47,12 +47,8 @@  #include <errno.h>  #include <malloc.h>  #include <watchdog.h> -#include <serial.h>  #include <linux/stddef.h>  #include <asm/byteorder.h> -#if defined(CONFIG_CMD_NET) -#include <net.h> -#endif  DECLARE_GLOBAL_DATA_PTR; @@ -76,16 +72,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE   */  #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */ -ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */ -ulong save_addr;			/* Default Save Address */ -ulong save_size;			/* Default Save Size (in bytes) */ - -/* - * Table with supported baudrates (defined in config_xyz.h) - */ -static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; -#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) -  /*   * This variable is incremented on each do_env_set(), so it can   * be used via get_env_id() as an indication, if the environment @@ -106,7 +92,7 @@ int get_env_id(void)   *   * Returns 0 in case of error, or length of printed string   */ -static int env_print(char *name) +static int env_print(char *name, int flag)  {  	char *res = NULL;  	size_t len; @@ -116,7 +102,7 @@ static int env_print(char *name)  		e.key = name;  		e.data = NULL; -		hsearch_r(e, FIND, &ep, &env_htab); +		hsearch_r(e, FIND, &ep, &env_htab, flag);  		if (ep == NULL)  			return 0;  		len = printf("%s=%s\n", ep->key, ep->data); @@ -124,7 +110,7 @@ static int env_print(char *name)  	}  	/* print whole list */ -	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL); +	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);  	if (len > 0) {  		puts(res); @@ -141,10 +127,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,  {  	int i;  	int rcode = 0; +	int env_flag = H_HIDE_DOT; + +	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { +		argc--; +		argv++; +		env_flag &= ~H_HIDE_DOT; +	}  	if (argc == 1) {  		/* print all env vars */ -		rcode = env_print(NULL); +		rcode = env_print(NULL, env_flag);  		if (!rcode)  			return 1;  		printf("\nEnvironment size: %d/%ld bytes\n", @@ -153,8 +146,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,  	}  	/* print selected env vars */ +	env_flag &= ~H_HIDE_DOT;  	for (i = 1; i < argc; ++i) { -		int rc = env_print(argv[i]); +		int rc = env_print(argv[i], env_flag);  		if (!rc) {  			printf("## Error: \"%s\" not defined\n", argv[i]);  			++rcode; @@ -198,137 +192,32 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,  #endif /* CONFIG_SPL_BUILD */  /* - * Perform consistency checking before setting, replacing, or deleting an - * environment variable, then (if successful) apply the changes to internals so - * to make them effective.  Code for this function was taken out of - * _do_env_set(), which now calls it instead. - * Also called as a callback function by himport_r(). - * Returns 0 in case of success, 1 in case of failure. - * When (flag & H_FORCE) is set, do not print out any error message and force - * overwriting of write-once variables. - */ - -int env_check_apply(const char *name, const char *oldval, -			const char *newval, int flag) -{ -	int   console = -1; - -	/* Default value for NULL to protect string-manipulating functions */ -	newval = newval ? : ""; - -	/* Check for console redirection */ -	if (strcmp(name, "stdin") == 0) -		console = stdin; -	else if (strcmp(name, "stdout") == 0) -		console = stdout; -	else if (strcmp(name, "stderr") == 0) -		console = stderr; - -	if (console != -1) { -		if ((newval == NULL) || (*newval == '\0')) { -			/* We cannot delete stdin/stdout/stderr */ -			if ((flag & H_FORCE) == 0) -				printf("Can't delete \"%s\"\n", name); -			return 1; -		} - -#ifdef CONFIG_CONSOLE_MUX -		if (iomux_doenv(console, newval)) -			return 1; -#else -		/* Try assigning specified device */ -		if (console_assign(console, newval) < 0) -			return 1; -#endif /* CONFIG_CONSOLE_MUX */ -	} - -	/* -	 * Some variables like "ethaddr" and "serial#" can be set only once and -	 * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. -	 */ -#ifndef CONFIG_ENV_OVERWRITE -	if (oldval != NULL &&			/* variable exists */ -		(flag & H_FORCE) == 0) {	/* and we are not forced */ -		if (strcmp(name, "serial#") == 0 || -		    (strcmp(name, "ethaddr") == 0 -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) -		     && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 -#endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ -			)) { -			printf("Can't overwrite \"%s\"\n", name); -			return 1; -		} -	} -#endif -	/* -	 * When we change baudrate, or we are doing an env default -a -	 * (which will erase all variables prior to calling this), -	 * we want the baudrate to actually change - for real. -	 */ -	if (oldval != NULL ||			/* variable exists */ -		(flag & H_NOCLEAR) == 0) {	/* or env is clear */ -		/* -		 * Switch to new baudrate if new baudrate is supported -		 */ -		if (strcmp(name, "baudrate") == 0) { -			int baudrate = simple_strtoul(newval, NULL, 10); -			int i; -			for (i = 0; i < N_BAUDRATES; ++i) { -				if (baudrate == baudrate_table[i]) -					break; -			} -			if (i == N_BAUDRATES) { -				if ((flag & H_FORCE) == 0) -					printf("## Baudrate %d bps not " -						"supported\n", baudrate); -				return 1; -			} -			if (gd->baudrate == baudrate) { -				/* If unchanged, we just say it's OK */ -				return 0; -			} -			printf("## Switch baudrate to %d bps and" -				"press ENTER ...\n", baudrate); -			udelay(50000); -			gd->baudrate = baudrate; -#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) -			gd->bd->bi_baudrate = baudrate; -#endif - -			serial_setbrg(); -			udelay(50000); -			while (getc() != '\r') -				; -		} -	} - -	/* -	 * Some variables should be updated when the corresponding -	 * entry in the environment is changed -	 */ -	if (strcmp(name, "loadaddr") == 0) { -		load_addr = simple_strtoul(newval, NULL, 16); -		return 0; -	} -#if defined(CONFIG_CMD_NET) -	else if (strcmp(name, "bootfile") == 0) { -		copy_filename(BootFile, newval, sizeof(BootFile)); -		return 0; -	} -#endif -	return 0; -} - -/*   * Set a new environment variable,   * or replace or delete an existing one. -*/ + */  static int _do_env_set(int flag, int argc, char * const argv[])  {  	int   i, len;  	char  *name, *value, *s;  	ENTRY e, *ep; +	int env_flag = H_INTERACTIVE; +	debug("Initial value for argc=%d\n", argc); +	while (argc > 1 && **(argv + 1) == '-') { +		char *arg = *++argv; + +		--argc; +		while (*++arg) { +			switch (*arg) { +			case 'f':		/* force */ +				env_flag |= H_FORCE; +				break; +			default: +				return CMD_RET_USAGE; +			} +		} +	} +	debug("Final value for argc=%d\n", argc);  	name = argv[1];  	value = argv[2]; @@ -339,25 +228,10 @@ static int _do_env_set(int flag, int argc, char * const argv[])  	}  	env_id++; -	/* -	 * search if variable with this name already exists -	 */ -	e.key = name; -	e.data = NULL; -	hsearch_r(e, FIND, &ep, &env_htab); - -	/* -	 * Perform requested checks. Notice how since we are overwriting -	 * a single variable, we need to set H_NOCLEAR -	 */ -	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { -		debug("check function did not approve, refusing\n"); -		return 1; -	}  	/* Delete only ? */  	if (argc < 3 || argv[2] == NULL) { -		int rc = hdelete_r(name, &env_htab, 0); +		int rc = hdelete_r(name, &env_htab, env_flag);  		return !rc;  	} @@ -384,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])  	e.key	= name;  	e.data	= value; -	hsearch_r(e, ENTER, &ep, &env_htab); +	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);  	free(value);  	if (!ep) {  		printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -511,6 +385,153 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  }  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +static int print_static_binding(const char *var_name, const char *callback_name) +{ +	printf("\t%-20s %-20s\n", var_name, callback_name); + +	return 0; +} + +static int print_active_callback(ENTRY *entry) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks; + +	if (entry->callback == NULL) +		return 0; + +	/* look up the callback in the linker-list */ +	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) { +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +		if (entry->callback == clbkp->callback + gd->reloc_off) +#else +		if (entry->callback == clbkp->callback) +#endif +			break; +	} + +	if (i == num_callbacks) +		/* this should probably never happen, but just in case... */ +		printf("\t%-20s %p\n", entry->key, entry->callback); +	else +		printf("\t%-20s %-20s\n", entry->key, clbkp->name); + +	return 0; +} + +/* + * Print the callbacks available and what they are bound to + */ +int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks; + +	/* Print the available callbacks */ +	puts("Available callbacks:\n"); +	puts("\tCallback Name\n"); +	puts("\t-------------\n"); +	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) +		printf("\t%s\n", clbkp->name); +	puts("\n"); + +	/* Print the static bindings that may exist */ +	puts("Static callback bindings:\n"); +	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); +	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding); +	puts("\n"); + +	/* walk through each variable and print the callback if it has one */ +	puts("Active callback bindings:\n"); +	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); +	printf("\t%-20s %-20s\n", "-------------", "-------------"); +	hwalk_r(&env_htab, print_active_callback); +	return 0; +} +#endif + +#if defined(CONFIG_CMD_ENV_FLAGS) +static int print_static_flags(const char *var_name, const char *flags) +{ +	enum env_flags_vartype type = env_flags_parse_vartype(flags); +	enum env_flags_varaccess access = env_flags_parse_varaccess(flags); + +	printf("\t%-20s %-20s %-20s\n", var_name, +		env_flags_get_vartype_name(type), +		env_flags_get_varaccess_name(access)); + +	return 0; +} + +static int print_active_flags(ENTRY *entry) +{ +	enum env_flags_vartype type; +	enum env_flags_varaccess access; + +	if (entry->flags == 0) +		return 0; + +	type = (enum env_flags_vartype) +		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); +	access = env_flags_parse_varaccess_from_binflags(entry->flags); +	printf("\t%-20s %-20s %-20s\n", entry->key, +		env_flags_get_vartype_name(type), +		env_flags_get_varaccess_name(access)); + +	return 0; +} + +/* + * Print the flags available and what variables have flags + */ +int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	/* Print the available variable types */ +	printf("Available variable type flags (position %d):\n", +		ENV_FLAGS_VARTYPE_LOC); +	puts("\tFlag\tVariable Type Name\n"); +	puts("\t----\t------------------\n"); +	env_flags_print_vartypes(); +	puts("\n"); + +	/* Print the available variable access types */ +	printf("Available variable access flags (position %d):\n", +		ENV_FLAGS_VARACCESS_LOC); +	puts("\tFlag\tVariable Access Name\n"); +	puts("\t----\t--------------------\n"); +	env_flags_print_varaccess(); +	puts("\n"); + +	/* Print the static flags that may exist */ +	puts("Static flags:\n"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------"); +	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); +	puts("\n"); + +	/* walk through each variable and print the flags if non-default */ +	puts("Active flags:\n"); +	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", +		"Variable Access"); +	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", +		"---------------"); +	hwalk_r(&env_htab, print_active_flags); +	return 0; +} +#endif +  /*   * Interactively edit an environment variable   */ @@ -552,7 +573,7 @@ char *getenv(const char *name)  		e.key	= name;  		e.data	= NULL; -		hsearch_r(e, FIND, &ep, &env_htab); +		hsearch_r(e, FIND, &ep, &env_htab, 0);  		return ep ? ep->data : NULL;  	} @@ -704,8 +725,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag,  static int do_env_delete(cmd_tbl_t *cmdtp, int flag,  			 int argc, char * const argv[])  { -	printf("Not implemented yet\n"); -	return 0; +	int env_flag = H_INTERACTIVE; +	int ret = 0; + +	debug("Initial value for argc=%d\n", argc); +	while (argc > 1 && **(argv + 1) == '-') { +		char *arg = *++argv; + +		--argc; +		while (*++arg) { +			switch (*arg) { +			case 'f':		/* force */ +				env_flag |= H_FORCE; +				break; +			default: +				return CMD_RET_USAGE; +			} +		} +	} +	debug("Final value for argc=%d\n", argc); + +	env_id++; + +	while (--argc > 0) { +		char *name = *++argv; + +		if (!hdelete_r(name, &env_htab, env_flag)) +			ret = 1; +	} + +	return ret;  }  #ifdef CONFIG_CMD_EXPORTENV @@ -812,7 +861,7 @@ NXTARG:		;  	argv++;  	if (sep) {		/* export as text file */ -		len = hexport_r(&env_htab, sep, &addr, size, argc, argv); +		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);  		if (len < 0) {  			error("Cannot export environment: errno = %d\n", errno);  			return 1; @@ -830,7 +879,7 @@ NXTARG:		;  	else			/* export as raw binary data */  		res = addr; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -951,7 +1000,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,  	}  	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, -			0, NULL, 0 /* do_apply */) == 0) { +			0, NULL) == 0) {  		error("Environment import failed: errno = %d\n", errno);  		return 1;  	} @@ -974,10 +1023,16 @@ static cmd_tbl_t cmd_env_sub[] = {  	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),  #endif  	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), -	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""), +	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),  #if defined(CONFIG_CMD_EDITENV)  	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), +#endif +#if defined(CONFIG_CMD_ENV_FLAGS) +	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), +#endif  #if defined(CONFIG_CMD_EXPORTENV)  	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),  #endif @@ -1028,21 +1083,28 @@ static char env_help_text[] =  #if defined(CONFIG_CMD_ASKENV)  	"ask name [message] [size] - ask for environment variable\nenv "  #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +	"callbacks - print callbacks and their associated variables\nenv " +#endif  	"default [-f] -a - [forcibly] reset default environment\n"  	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" +	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"  #if defined(CONFIG_CMD_EDITENV)  	"env edit name - edit environment variable\n"  #endif  #if defined(CONFIG_CMD_EXPORTENV)  	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"  #endif +#if defined(CONFIG_CMD_ENV_FLAGS) +	"env flags - print variables that have non-default flags\n" +#endif  #if defined(CONFIG_CMD_GREPENV)  	"env grep string [...] - search environment\n"  #endif  #if defined(CONFIG_CMD_IMPORTENV)  	"env import [-d] [-t | -b | -c] addr [size] - import environment\n"  #endif -	"env print [name ...] - print environment\n" +	"env print [-a | name ...] - print environment\n"  #if defined(CONFIG_CMD_RUN)  	"env run var [...] - run commands in an environment variable\n"  #endif @@ -1074,7 +1136,7 @@ U_BOOT_CMD_COMPLETE(  U_BOOT_CMD_COMPLETE(  	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,  	"print environment variables", -	"\n    - print values of all environment variables\n" +	"[-a]\n    - print [all] values of all environment variables\n"  	"printenv name ...\n"  	"    - print value of environment variable 'name'",  	var_complete @@ -1093,10 +1155,10 @@ U_BOOT_CMD_COMPLETE(  U_BOOT_CMD_COMPLETE(  	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,  	"set environment variables", -	"name value ...\n" -	"    - set environment variable 'name' to 'value ...'\n" -	"setenv name\n" -	"    - delete environment variable 'name'", +	"[-f] name value ...\n" +	"    - [forcibly] set environment variable 'name' to 'value ...'\n" +	"setenv [-f] name\n" +	"    - [forcibly] delete environment variable 'name'",  	var_complete  ); diff --git a/common/cmd_read.c b/common/cmd_read.c new file mode 100644 index 000000000..f0fc9bfe1 --- /dev/null +++ b/common/cmd_read.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <part.h> + +int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	char *ep; +	block_dev_desc_t *dev_desc = NULL; +	int dev; +	int part = 0; +	disk_partition_t part_info; +	ulong offset = 0u; +	ulong limit = 0u; +	void *addr; +	uint blk; +	uint cnt; + +	if (argc != 6) { +		cmd_usage(cmdtp); +		return 1; +	} + +	dev = (int)simple_strtoul(argv[2], &ep, 16); +	if (*ep) { +		if (*ep != ':') { +			printf("Invalid block device %s\n", argv[2]); +			return 1; +		} +		part = (int)simple_strtoul(++ep, NULL, 16); +	} + +	dev_desc = get_dev(argv[1], dev); +	if (dev_desc == NULL) { +		printf("Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} + +	addr = (void *)simple_strtoul(argv[3], NULL, 16); +	blk = simple_strtoul(argv[4], NULL, 16); +	cnt = simple_strtoul(argv[5], NULL, 16); + +	if (part != 0) { +		if (get_partition_info(dev_desc, part, &part_info)) { +			printf("Cannot find partition %d\n", part); +			return 1; +		} +		offset = part_info.start; +		limit = part_info.size; +	} else { +		/* Largest address not available in block_dev_desc_t. */ +		limit = ~0; +	} + +	if (cnt + blk > limit) { +		printf("Read out of range\n"); +		return 1; +	} + +	if (dev_desc->block_read(dev, offset + blk, cnt, addr) < 0) { +		printf("Error reading blocks\n"); +		return 1; +	} + +	return 0; +} + +U_BOOT_CMD( +	read,	6,	0,	do_read, +	"Load binary data from a partition", +	"<interface> <dev[:part]> addr blk# cnt" +); diff --git a/common/cmd_sha1sum.c b/common/cmd_sha1sum.c index 8db5456c9..fe927ab24 100644 --- a/common/cmd_sha1sum.c +++ b/common/cmd_sha1sum.c @@ -26,73 +26,11 @@  #include <common.h>  #include <command.h> +#include <hash.h>  #include <sha1.h> -/* - * Store the resulting sum to an address or variable - */ -static void store_result(const u8 *sum, const char *dest) -{ -	unsigned int i; - -	if (*dest == '*') { -		u8 *ptr; - -		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); -		for (i = 0; i < 20; i++) -			*ptr++ = sum[i]; -	} else { -		char str_output[41]; -		char *str_ptr = str_output; - -		for (i = 0; i < 20; i++) { -			sprintf(str_ptr, "%02x", sum[i]); -			str_ptr += 2; -		} -		str_ptr = '\0'; -		setenv(dest, str_output); -	} -} - -#ifdef CONFIG_SHA1SUM_VERIFY -static int parse_verify_sum(char *verify_str, u8 *vsum) -{ -	if (*verify_str == '*') { -		u8 *ptr; - -		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); -		memcpy(vsum, ptr, 20); -	} else { -		unsigned int i; -		char *vsum_str; - -		if (strlen(verify_str) == 40) -			vsum_str = verify_str; -		else { -			vsum_str = getenv(verify_str); -			if (vsum_str == NULL || strlen(vsum_str) != 40) -				return 1; -		} - -		for (i = 0; i < 20; i++) { -			char *nullp = vsum_str + (i + 1) * 2; -			char end = *nullp; - -			*nullp = '\0'; -			*(u8 *)(vsum + i) = -				simple_strtoul(vsum_str + (i * 2), NULL, 16); -			*nullp = end; -		} -	} -	return 0; -} -  int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	ulong addr, len; -	unsigned int i; -	u8 output[20]; -	u8 vsum[20];  	int verify = 0;  	int ac;  	char * const *av; @@ -102,75 +40,16 @@ int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	av = argv + 1;  	ac = argc - 1; +#ifdef CONFIG_SHA1SUM_VERIFY  	if (strcmp(*av, "-v") == 0) {  		verify = 1;  		av++;  		ac--; -		if (ac < 3) -			return CMD_RET_USAGE;  	} +#endif -	addr = simple_strtoul(*av++, NULL, 16); -	len = simple_strtoul(*av++, NULL, 16); - -	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); - -	if (!verify) { -		printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); -		for (i = 0; i < 20; i++) -			printf("%02x", output[i]); -		printf("\n"); - -		if (ac > 2) -			store_result(output, *av); -	} else { -		char *verify_str = *av++; - -		if (parse_verify_sum(verify_str, vsum)) { -			printf("ERROR: %s does not contain a valid SHA1 sum\n", -				verify_str); -			return 1; -		} -		if (memcmp(output, vsum, 20) != 0) { -			printf("SHA1 for %08lx ... %08lx ==> ", addr, -				addr + len - 1); -			for (i = 0; i < 20; i++) -				printf("%02x", output[i]); -			printf(" != "); -			for (i = 0; i < 20; i++) -				printf("%02x", vsum[i]); -			printf(" ** ERROR **\n"); -			return 1; -		} -	} - -	return 0; -} -#else -static int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ -	unsigned long addr, len; -	unsigned int i; -	u8 output[20]; - -	if (argc < 3) -		return CMD_RET_USAGE; - -	addr = simple_strtoul(argv[1], NULL, 16); -	len = simple_strtoul(argv[2], NULL, 16); - -	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); -	printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); -	for (i = 0; i < 20; i++) -		printf("%02x", output[i]); -	printf("\n"); - -	if (argc > 3) -		store_result(output, argv[3]); - -	return 0; +	return hash_command("sha1", verify, cmdtp, flag, ac, av);  } -#endif  #ifdef CONFIG_SHA1SUM_VERIFY  U_BOOT_CMD( diff --git a/common/cmd_spl.c b/common/cmd_spl.c index 9ec054af3..e3c543b46 100644 --- a/common/cmd_spl.c +++ b/common/cmd_spl.c @@ -130,10 +130,12 @@ static int spl_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		if (call_bootm(argc, argv, subcmd_list[(int)c->cmd]))  			return -1;  		switch ((int)c->cmd) { +#ifdef CONFIG_OF_LIBFDT  		case SPL_EXPORT_FDT:  			printf("Argument image is now in RAM: 0x%p\n",  				(void *)images.ft_addr);  			break; +#endif  		case SPL_EXPORT_ATAGS:  			printf("Argument image is now in RAM at: 0x%p\n",  				(void *)gd->bd->bi_boot_params); diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c index 6f5cd4895..0970a6fc1 100644 --- a/common/cmd_tpm.c +++ b/common/cmd_tpm.c @@ -63,19 +63,68 @@ static int tpm_process(int argc, char * const argv[], cmd_tbl_t *cmdtp)  	return rv;  } -static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +#define CHECK(exp) do {							\ +		int _rv = exp;						\ +		if (_rv) {						\ +			printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ +		}							\ +	} while (0) + +static int tpm_process_stress(int repeat_count)  { +	int i;  	int rv = 0; +	u8 request[] = {0x0, 0xc1, +			0x0, 0x0, 0x0, 0x16, +			0x0, 0x0, 0x0, 0x65, +			0x0, 0x0, 0x0, 0x4, +			0x0, 0x0, 0x0, 0x4, +			0x0, 0x0, 0x1, 0x9}; +	u8 response[MAX_TRANSACTION_SIZE]; +	u32 rlength = MAX_TRANSACTION_SIZE; + +	CHECK(tis_init()); + +	for (i = 0; i < repeat_count; i++) { +		CHECK(tis_open()); +		rv = tis_sendrecv(request, sizeof(request), response, &rlength); +		if (rv) { +			printf("tpm test failed at step %d with 0x%x\n", i, rv); +			CHECK(tis_close()); +			break; +		} +		CHECK(tis_close()); +		if ((response[6] || response[7] || response[8] || response[9]) +		    && response[9] != 0x26) { +			/* Ignore postinit errors */ +			printf("tpm command failed at step %d\n" +			       "tpm error code: %02x%02x%02x%02x\n", i, +			       response[6], response[7], +			       response[8], response[9]); +			rv = -1; +			break; +		} +	} +	return rv; +} -	/* -	 * Verify that in case it is present, the first argument, it is -	 * exactly one character in size. -	 */ -	if (argc < 7) { + +static int do_tpm_many(cmd_tbl_t *cmdtp, int flag, +		       int argc, char * const argv[], int repeat_count) + +{ +	int rv = 0; + +	if (argc < 7 && repeat_count == 0) {  		puts("command should be at least six bytes in size\n");  		return -1;  	} +	if (repeat_count > 0) { +		rv = tpm_process_stress(repeat_count); +		return rv; +	} +  	if (tis_init()) {  		puts("tis_init() failed!\n");  		return -1; @@ -96,8 +145,40 @@ static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	return rv;  } + +static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	return do_tpm_many(cmdtp, flag, argc, argv, 0); +} + +  U_BOOT_CMD(tpm, MAX_TRANSACTION_SIZE, 1, do_tpm,  	   "<byte> [<byte> ...]   - write data and read response",  	   "send arbitrary data (at least 6 bytes) to the TPM "  	   "device and read the response"  ); + +static int do_tpm_stress(cmd_tbl_t *cmdtp, int flag, +			 int argc, char * const argv[]) +{ +	long unsigned int n; +	int rv; + +	if (argc != 2) { +		puts("usage: tpm_stress <count>\n"); +		return -1; +	} + +	rv = strict_strtoul(argv[1], 10, &n); +	if (rv) { +		puts("tpm_stress: bad count"); +		return -1; +	} + +	return do_tpm_many(cmdtp, flag, argc, argv, n); +} + +U_BOOT_CMD(tpm_stress, 2, 1, do_tpm_stress, +	   "<n>   - stress-test communication with TPM", +	   "Repeat a TPM transaction (request-response) N times" +); diff --git a/common/cmd_usb.c b/common/cmd_usb.c index 8ad0b2305..dacdc2d5b 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -192,7 +192,7 @@ static void usb_display_desc(struct usb_device *dev)  } -static void usb_display_conf_desc(struct usb_configuration_descriptor *config, +static void usb_display_conf_desc(struct usb_config_descriptor *config,  				  struct usb_device *dev)  {  	printf("   Configuration: %d\n", config->bConfigurationValue); diff --git a/common/console.c b/common/console.c index 1177f7d39..bf7317869 100644 --- a/common/console.c +++ b/common/console.c @@ -24,11 +24,78 @@  #include <common.h>  #include <stdarg.h>  #include <malloc.h> +#include <serial.h>  #include <stdio_dev.h>  #include <exports.h> +#include <environment.h>  DECLARE_GLOBAL_DATA_PTR; +static int on_console(const char *name, const char *value, enum env_op op, +	int flags) +{ +	int console = -1; + +	/* Check for console redirection */ +	if (strcmp(name, "stdin") == 0) +		console = stdin; +	else if (strcmp(name, "stdout") == 0) +		console = stdout; +	else if (strcmp(name, "stderr") == 0) +		console = stderr; + +	/* if not actually setting a console variable, we don't care */ +	if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0) +		return 0; + +	switch (op) { +	case env_op_create: +	case env_op_overwrite: + +#ifdef CONFIG_CONSOLE_MUX +		if (iomux_doenv(console, value)) +			return 1; +#else +		/* Try assigning specified device */ +		if (console_assign(console, value) < 0) +			return 1; +#endif /* CONFIG_CONSOLE_MUX */ +		return 0; + +	case env_op_delete: +		if ((flags & H_FORCE) == 0) +			printf("Can't delete \"%s\"\n", name); +		return 1; + +	default: +		return 0; +	} +} +U_BOOT_ENV_CALLBACK(console, on_console); + +#ifdef CONFIG_SILENT_CONSOLE +static int on_silent(const char *name, const char *value, enum env_op op, +	int flags) +{ +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET +	if (flags & H_INTERACTIVE) +		return 0; +#endif +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC +	if ((flags & H_INTERACTIVE) == 0) +		return 0; +#endif + +	if (value != NULL) +		gd->flags |= GD_FLG_SILENT; +	else +		gd->flags &= ~GD_FLG_SILENT; + +	return 0; +} +U_BOOT_ENV_CALLBACK(silent, on_silent); +#endif +  #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV  /*   * if overwrite_console returns 1, the stdin, stderr and stdout @@ -591,7 +658,6 @@ int console_init_f(void)  void stdio_print_current_devices(void)  { -#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	/* Print information */  	puts("In:    ");  	if (stdio_devices[stdin] == NULL) { @@ -613,7 +679,6 @@ void stdio_print_current_devices(void)  	} else {  		printf ("%s\n", stdio_devices[stderr]->name);  	} -#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  }  #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV @@ -683,9 +748,9 @@ int console_init_r(void)  done:  #endif -	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE  	/* set the environment variables (will overwrite previous env settings) */ @@ -694,6 +759,8 @@ done:  	}  #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ +	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ +  #if 0  	/* If nothing usable installed, use only the initial console */  	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) @@ -758,15 +825,17 @@ int console_init_r(void)  #endif  	} -	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET  	stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */  	/* Setting environment variables */  	for (i = 0; i < 3; i++) {  		setenv(stdio_names[i], stdio_devices[i]->name);  	} +	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */ +  #if 0  	/* If nothing usable installed, use only the initial console */  	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) diff --git a/common/edid.c b/common/edid.c new file mode 100644 index 000000000..c82c29809 --- /dev/null +++ b/common/edid.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2010 + * Petr Stetiar <ynezz@true.cz> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Contains stolen code from ddcprobe project which is: + * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> + * + */ + +#include <common.h> +#include <edid.h> +#include <linux/ctype.h> +#include <linux/string.h> + +int edid_check_info(struct edid1_info *edid_info) +{ +	if ((edid_info == NULL) || (edid_info->version == 0)) +		return -1; + +	if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8)) +		return -1; + +	if (edid_info->version == 0xff && edid_info->revision == 0xff) +		return -1; + +	return 0; +} + +int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, +		    unsigned int *hmax, unsigned int *vmin, +		    unsigned int *vmax) +{ +	int i; +	struct edid_monitor_descriptor *monitor; + +	*hmin = *hmax = *vmin = *vmax = 0; +	if (edid_check_info(edid)) +		return -1; + +	for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) { +		monitor = &edid->monitor_details.descriptor[i]; +		if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) { +			*hmin = monitor->data.range_data.horizontal_min; +			*hmax = monitor->data.range_data.horizontal_max; +			*vmin = monitor->data.range_data.vertical_min; +			*vmax = monitor->data.range_data.vertical_max; +			return 0; +		} +	} +	return -1; +} + +/** + * Snip the tailing whitespace/return of a string. + * + * @param string	The string to be snipped + * @return the snipped string + */ +static char *snip(char *string) +{ +	char *s; + +	/* +	 * This is always a 13 character buffer +	 * and it's not always terminated. +	 */ +	string[12] = '\0'; +	s = &string[strlen(string) - 1]; + +	while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' || +			*s == '\0')) +		*(s--) = '\0'; + +	return string; +} + +/** + * Print an EDID monitor descriptor block + * + * @param monitor	The EDID monitor descriptor block + * @have_timing		Modifies to 1 if the desciptor contains timing info + */ +static void edid_print_dtd(struct edid_monitor_descriptor *monitor, +			   unsigned int *have_timing) +{ +	unsigned char *bytes = (unsigned char *)monitor; +	struct edid_detailed_timing *timing = +			(struct edid_detailed_timing *)monitor; + +	if (bytes[0] == 0 && bytes[1] == 0) { +		if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL) +			printf("Monitor serial number: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII) +			printf("Monitor ID: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME) +			printf("Monitor name: %s\n", +			       snip(monitor->data.string)); +		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) +			printf("Monitor range limits, horizontal sync: " +			       "%d-%d kHz, vertical refresh: " +			       "%d-%d Hz, max pixel clock: " +			       "%d MHz\n", +			       monitor->data.range_data.horizontal_min, +			       monitor->data.range_data.horizontal_max, +			       monitor->data.range_data.vertical_min, +			       monitor->data.range_data.vertical_max, +			       monitor->data.range_data.pixel_clock_max * 10); +	} else { +		uint32_t pixclock, h_active, h_blanking, v_active, v_blanking; +		uint32_t h_total, v_total, vfreq; + +		pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing); +		h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing); +		h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing); +		v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing); +		v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing); + +		h_total = h_active + h_blanking; +		v_total = v_active + v_blanking; +		if (v_total * h_total) +			vfreq = pixclock / (v_total * h_total); +		else +			vfreq = 1; /* Error case */ +		printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active, +		       v_active, h_active > 1000 ? ' ' : '\t', vfreq); +		*have_timing = 1; +	} +} + +/** + * Get the manufacturer name from an EDID info. + * + * @param edid_info     The EDID info to be printed + * @param name		Returns the string of the manufacturer name + */ +static void edid_get_manufacturer_name(struct edid1_info *edid, char *name) +{ +	name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1; +	name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1; +	name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1; +	name[3] = '\0'; +} + +void edid_print_info(struct edid1_info *edid_info) +{ +	int i; +	char manufacturer[4]; +	unsigned int have_timing = 0; +	uint32_t serial_number; + +	if (edid_check_info(edid_info)) { +		printf("Not a valid EDID\n"); +		return; +	} + +	printf("EDID version: %d.%d\n", +	       edid_info->version, edid_info->revision); + +	printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info)); + +	edid_get_manufacturer_name(edid_info, manufacturer); +	printf("Manufacturer: %s\n", manufacturer); + +	serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info); +	if (serial_number != 0xffffffff) { +		if (strcmp(manufacturer, "MAG") == 0) +			serial_number -= 0x7000000; +		if (strcmp(manufacturer, "OQI") == 0) +			serial_number -= 456150000; +		if (strcmp(manufacturer, "VSC") == 0) +			serial_number -= 640000000; +	} +	printf("Serial number: %08x\n", serial_number); +	printf("Manufactured in week: %d year: %d\n", +	       edid_info->week, edid_info->year + 1990); + +	printf("Video input definition: %svoltage level %d%s%s%s%s%s\n", +	       EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ? +	       "digital signal, " : "analog signal, ", +	       EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info), +	       EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ? +	       ", blank to black" : "", +	       EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ? +	       ", separate sync" : "", +	       EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ? +	       ", composite sync" : "", +	       EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ? +	       ", sync on green" : "", +	       EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ? +	       ", serration v" : ""); + +	printf("Monitor is %s\n", +	       EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB"); + +	printf("Maximum visible display size: %d cm x %d cm\n", +	       edid_info->max_size_horizontal, +	       edid_info->max_size_vertical); + +	printf("Power management features: %s%s, %s%s, %s%s\n", +	       EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ? +	       "" : "no ", "active off", +	       EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend", +	       EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby"); + +	printf("Estabilished timings:\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info)) +		printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info)) +		printf("\t720x400\t\t88 Hz (XGA2)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info)) +		printf("\t640x480\t\t60 Hz (VGA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info)) +		printf("\t640x480\t\t67 Hz (Mac II, Apple)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info)) +		printf("\t640x480\t\t72 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info)) +		printf("\t640x480\t\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info)) +		printf("\t800x600\t\t56 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info)) +		printf("\t800x600\t\t60 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info)) +		printf("\t800x600\t\t72 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info)) +		printf("\t800x600\t\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info)) +		printf("\t832x624\t\t75 Hz (Mac II)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info)) +		printf("\t1024x768\t87 Hz Interlaced (8514A)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info)) +		printf("\t1024x768\t60 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info)) +		printf("\t1024x768\t70 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info)) +		printf("\t1024x768\t75 Hz (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info)) +		printf("\t1280x1024\t75 (VESA)\n"); +	if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info)) +		printf("\t1152x870\t75 (Mac II)\n"); + +	/* Standard timings. */ +	printf("Standard timings:\n"); +	for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) { +		unsigned int aspect = 10000; +		unsigned int x, y; +		unsigned char xres, vfreq; + +		xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i); +		vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i); +		if ((xres != vfreq) || +		    ((xres != 0) && (xres != 1)) || +		    ((vfreq != 0) && (vfreq != 1))) { +			switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info, +					i)) { +			case ASPECT_625: +				aspect = 6250; +				break; +			case ASPECT_75: +				aspect = 7500; +				break; +			case ASPECT_8: +				aspect = 8000; +				break; +			case ASPECT_5625: +				aspect = 5625; +				break; +			} +			x = (xres + 31) * 8; +			y = x * aspect / 10000; +			printf("\t%dx%d%c\t%d Hz\n", x, y, +			       x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60); +			have_timing = 1; +		} +	} + +	/* Detailed timing information. */ +	for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor); +			i++) { +		edid_print_dtd(&edid_info->monitor_details.descriptor[i], +			       &have_timing); +	} + +	if (!have_timing) +		printf("\tNone\n"); +} diff --git a/common/env_attr.c b/common/env_attr.c new file mode 100644 index 000000000..210c98dcf --- /dev/null +++ b/common/env_attr.c @@ -0,0 +1,229 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include <linux/linux_string.h> +#else +#include <common.h> +#endif + +#include <env_attr.h> +#include <errno.h> +#include <linux/string.h> +#include <malloc.h> + +/* + * Iterate through the whole list calling the callback for each found element. + * "attr_list" takes the form: + *	attributes = [^,:\s]* + *	entry = name[:attributes] + *	list = entry[,list] + */ +int env_attr_walk(const char *attr_list, +	int (*callback)(const char *name, const char *attributes)) +{ +	const char *entry, *entry_end; +	char *name, *attributes; + +	if (!attr_list) +		/* list not found */ +		return 1; + +	entry = attr_list; +	do { +		char *entry_cpy = NULL; + +		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); +		/* check if this is the last entry in the list */ +		if (entry_end == NULL) { +			int entry_len = strlen(entry); + +			if (entry_len) { +				/* +				 * allocate memory to copy the entry into since +				 * we will need to inject '\0' chars and squash +				 * white-space before calling the callback +				 */ +				entry_cpy = malloc(entry_len + 1); +				if (entry_cpy) +					/* copy the rest of the list */ +					strcpy(entry_cpy, entry); +				else +					return -ENOMEM; +			} +		} else { +			int entry_len = entry_end - entry; + +			if (entry_len) { +				/* +				 * allocate memory to copy the entry into since +				 * we will need to inject '\0' chars and squash +				 * white-space before calling the callback +				 */ +				entry_cpy = malloc(entry_len + 1); +				if (entry_cpy) { +					/* copy just this entry and null term */ +					strncpy(entry_cpy, entry, entry_len); +					entry_cpy[entry_len] = '\0'; +				} else +					return -ENOMEM; +			} +		} + +		/* check if there is anything to process (e.g. not ",,,") */ +		if (entry_cpy != NULL) { +			attributes = strchr(entry_cpy, ENV_ATTR_SEP); +			/* check if there is a ':' */ +			if (attributes != NULL) { +				/* replace the ':' with '\0' to term name */ +				*attributes++ = '\0'; +				/* remove white-space from attributes */ +				attributes = strim(attributes); +			} +			/* remove white-space from name */ +			name = strim(entry_cpy); + +			/* only call the callback if there is a name */ +			if (strlen(name) != 0) { +				int retval = 0; + +				retval = callback(name, attributes); +				if (retval) { +					free(entry_cpy); +					return retval; +				} +			} +		} + +		free(entry_cpy); +		entry = entry_end + 1; +	} while (entry_end != NULL); + +	return 0; +} + +/* + * Search for the last matching string in another string with the option to + * start looking at a certain point (i.e. ignore anything beyond that point). + */ +static char *reverse_strstr(const char *searched, const char *search_for, +	const char *searched_start) +{ +	char *result = NULL; + +	if (*search_for == '\0') +		return (char *)searched; + +	for (;;) { +		char *match = strstr(searched, search_for); + +		/* +		 * Stop looking if no new match is found or looking past the +		 * searched_start pointer +		 */ +		if (match == NULL || (searched_start != NULL && +		    match + strlen(search_for) > searched_start)) +			break; + +		result = match; +		searched = match + 1; +	} + +	return result; +} + +/* + * Retrieve the attributes string associated with a single name in the list + * There is no protection on attributes being too small for the value + */ +int env_attr_lookup(const char *attr_list, const char *name, char *attributes) +{ +	const char *entry = NULL; + +	if (!attributes) +		/* bad parameter */ +		return -1; +	if (!attr_list) +		/* list not found */ +		return 1; + +	entry = reverse_strstr(attr_list, name, NULL); +	while (entry != NULL) { +		const char *prevch = entry - 1; +		const char *nextch = entry + strlen(name); + +		/* Skip spaces */ +		while (*prevch == ' ') +			prevch--; +		while (*nextch == ' ') +			nextch++; + +		/* check for an exact match */ +		if ((entry == attr_list || +		     *prevch == ENV_ATTR_LIST_DELIM) && +		    (*nextch == ENV_ATTR_SEP || +		     *nextch == ENV_ATTR_LIST_DELIM || +		     *nextch == '\0')) +			break; + +		entry = reverse_strstr(attr_list, name, entry); +	} +	if (entry != NULL) { +		int len; + +		/* skip the name */ +		entry += strlen(name); +		/* skip spaces */ +		while (*entry == ' ') +			entry++; +		if (*entry != ENV_ATTR_SEP) +			len = 0; +		else { +			const char *delim; +			static const char delims[] = { +				ENV_ATTR_LIST_DELIM, ' ', '\0'}; + +			/* skip the attr sep */ +			entry += 1; +			/* skip spaces */ +			while (*entry == ' ') +				entry++; + +			delim = strpbrk(entry, delims); +			if (delim == NULL) +				len = strlen(entry); +			else +				len = delim - entry; +			memcpy(attributes, entry, len); +		} +		attributes[len] = '\0'; + +		/* success */ +		return 0; +	} + +	/* not found in list */ +	return 2; +} diff --git a/common/env_callback.c b/common/env_callback.c new file mode 100644 index 000000000..78ca3674f --- /dev/null +++ b/common/env_callback.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <environment.h> + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * Look up a callback function pointer by name + */ +struct env_clbk_tbl *find_env_callback(const char *name) +{ +	struct env_clbk_tbl *clbkp; +	int i; +	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + +	if (name == NULL) +		return NULL; + +	/* look up the callback in the linker-list */ +	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); +	     i < num_callbacks; +	     i++, clbkp++) { +		if (strcmp(name, clbkp->name) == 0) +			return clbkp; +	} + +	return NULL; +} + +/* + * Look for a possible callback for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_callback_init(ENTRY *var_entry) +{ +	const char *var_name = var_entry->key; +	const char *callback_list = getenv(ENV_CALLBACK_VAR); +	char callback_name[256] = ""; +	struct env_clbk_tbl *clbkp; +	int ret = 1; + +	/* look in the ".callbacks" var for a reference to this variable */ +	if (callback_list != NULL) +		ret = env_attr_lookup(callback_list, var_name, callback_name); + +	/* only if not found there, look in the static list */ +	if (ret) +		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, +			callback_name); + +	/* if an association was found, set the callback pointer */ +	if (!ret && strlen(callback_name)) { +		clbkp = find_env_callback(callback_name); +		if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +			var_entry->callback = clbkp->callback + gd->reloc_off; +#else +			var_entry->callback = clbkp->callback; +#endif +	} +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a callback association should remove its callback. + */ +static int clear_callback(ENTRY *entry) +{ +	entry->callback = NULL; + +	return 0; +} + +/* + * Call for each element in the list that associates variables to callbacks + */ +static int set_callback(const char *name, const char *value) +{ +	ENTRY e, *ep; +	struct env_clbk_tbl *clbkp; + +	e.key	= name; +	e.data	= NULL; +	hsearch_r(e, FIND, &ep, &env_htab, 0); + +	/* does the env variable actually exist? */ +	if (ep != NULL) { +		/* the assocaition delares no callback, so remove the pointer */ +		if (value == NULL || strlen(value) == 0) +			ep->callback = NULL; +		else { +			/* assign the requested callback */ +			clbkp = find_env_callback(value); +			if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +				ep->callback = clbkp->callback + gd->reloc_off; +#else +				ep->callback = clbkp->callback; +#endif +		} +	} + +	return 0; +} + +static int on_callbacks(const char *name, const char *value, enum env_op op, +	int flags) +{ +	/* remove all callbacks */ +	hwalk_r(&env_htab, clear_callback); + +	/* configure any static callback bindings */ +	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback); +	/* configure any dynamic callback bindings */ +	env_attr_walk(value, set_callback); + +	return 0; +} +U_BOOT_ENV_CALLBACK(callbacks, on_callbacks); diff --git a/common/env_common.c b/common/env_common.c index 3d3cb70a6..906b41fcc 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;  #include <env_default.h>  struct hsearch_data env_htab = { -	.apply = env_check_apply, +	.change_ok = env_flags_validate,  };  static uchar __env_get_char_spec(int index) @@ -81,13 +81,42 @@ const uchar *env_get_addr(int index)  		return &default_environment[index];  } +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var) +{ +	char *s = getenv(var); + +	if (s == NULL) +		return -1; +	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ? +		1 : 0; +} + +/* + * Look up the variable from the default environment + */ +char *getenv_default(const char *name) +{ +	char *ret_val; +	unsigned long really_valid = gd->env_valid; +	unsigned long real_gd_flags = gd->flags; + +	/* Pretend that the image is bad. */ +	gd->flags &= ~GD_FLG_ENV_READY; +	gd->env_valid = 0; +	ret_val = getenv(name); +	gd->env_valid = really_valid; +	gd->flags = real_gd_flags; +	return ret_val; +} +  void set_default_env(const char *s)  { -	/* -	 * By default, do not apply changes as they will eventually -	 * be applied by someone else -	 */ -	int do_apply = 0; +	int flags = 0; +  	if (sizeof(default_environment) > ENV_SIZE) {  		puts("*** Error - default environment is too large\n\n");  		return; @@ -99,14 +128,7 @@ void set_default_env(const char *s)  				"using default environment\n\n",  				s + 1);  		} else { -			/* -			 * This set_to_default was explicitly asked for -			 * by the user, as opposed to being a recovery -			 * mechanism.  Therefore we check every single -			 * variable and apply changes to the system -			 * right away (e.g. baudrate, console). -			 */ -			do_apply = 1; +			flags = H_INTERACTIVE;  			puts(s);  		}  	} else { @@ -114,8 +136,8 @@ void set_default_env(const char *s)  	}  	if (himport_r(&env_htab, (char *)default_environment, -			sizeof(default_environment), '\0', 0, -			0, NULL, do_apply) == 0) +			sizeof(default_environment), '\0', flags, +			0, NULL) == 0)  		error("Environment import failed: errno = %d\n", errno);  	gd->flags |= GD_FLG_ENV_READY; @@ -130,8 +152,8 @@ int set_default_vars(int nvars, char * const vars[])  	 * (and use \0 as a separator)  	 */  	return himport_r(&env_htab, (const char *)default_environment, -				sizeof(default_environment), '\0', H_NOCLEAR, -				nvars, vars, 1 /* do_apply */); +				sizeof(default_environment), '\0', +				H_NOCLEAR | H_INTERACTIVE, nvars, vars);  }  #ifndef CONFIG_SPL_BUILD @@ -155,7 +177,7 @@ int env_import(const char *buf, int check)  	}  	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, -			0, NULL, 0 /* do_apply */)) { +			0, NULL)) {  		gd->flags |= GD_FLG_ENV_READY;  		return 1;  	} @@ -172,6 +194,7 @@ void env_relocate(void)  {  #if defined(CONFIG_NEEDS_MANUAL_RELOC)  	env_reloc(); +	env_htab.change_ok += gd->reloc_off;  #endif  	if (gd->env_valid == 0) {  #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) diff --git a/common/env_dataflash.c b/common/env_dataflash.c index 3c5af37bf..38c96157b 100644 --- a/common/env_dataflash.c +++ b/common/env_dataflash.c @@ -60,7 +60,7 @@ int saveenv(void)  	char	*res;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_eeprom.c b/common/env_eeprom.c index b66bba29f..45c935b6d 100644 --- a/common/env_eeprom.c +++ b/common/env_eeprom.c @@ -139,7 +139,7 @@ int saveenv(void)  	BUG_ON(env_ptr != NULL);  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_fat.c b/common/env_fat.c index 6ef531821..c0f18ab97 100644 --- a/common/env_fat.c +++ b/common/env_fat.c @@ -61,7 +61,7 @@ int saveenv(void)  	int err;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_flags.c b/common/env_flags.c new file mode 100644 index 000000000..336cae4e9 --- /dev/null +++ b/common/env_flags.c @@ -0,0 +1,560 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <linux/string.h> +#include <linux/ctype.h> + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include "fw_env.h" +#include <env_attr.h> +#include <env_flags.h> +#define getenv fw_getenv +#else +#include <common.h> +#include <environment.h> +#endif + +#ifdef CONFIG_CMD_NET +#define ENV_FLAGS_NET_VARTYPE_REPS "im" +#else +#define ENV_FLAGS_NET_VARTYPE_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +static const char env_flags_varaccess_rep[] = "aroc"; +static const int env_flags_varaccess_mask[] = { +	0, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_CREATE | +		ENV_FLAGS_VARACCESS_PREVENT_OVERWR, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_OVERWR, +	ENV_FLAGS_VARACCESS_PREVENT_DELETE | +		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; + +#ifdef CONFIG_CMD_ENV_FLAGS +static const char * const env_flags_vartype_names[] = { +	"string", +	"decimal", +	"hexadecimal", +	"boolean", +#ifdef CONFIG_CMD_NET +	"IP address", +	"MAC address", +#endif +}; +static const char * const env_flags_varaccess_names[] = { +	"any", +	"read-only", +	"write-once", +	"change-default", +}; + +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void) +{ +	enum env_flags_vartype curtype = (enum env_flags_vartype)0; + +	while (curtype != env_flags_vartype_end) { +		printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype], +			env_flags_vartype_names[curtype]); +		curtype++; +	} +} + +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void) +{ +	enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0; + +	while (curaccess != env_flags_varaccess_end) { +		printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess], +			env_flags_varaccess_names[curaccess]); +		curaccess++; +	} +} + +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type) +{ +	return env_flags_vartype_names[type]; +} + +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access) +{ +	return env_flags_varaccess_names[access]; +} +#endif /* CONFIG_CMD_ENV_FLAGS */ + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags) +{ +	char *type; + +	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) +		return env_flags_vartype_string; + +	type = strchr(env_flags_vartype_rep, +		flags[ENV_FLAGS_VARTYPE_LOC]); + +	if (type != NULL) +		return (enum env_flags_vartype) +			(type - &env_flags_vartype_rep[0]); + +	printf("## Warning: Unknown environment variable type '%c'\n", +		flags[ENV_FLAGS_VARTYPE_LOC]); +	return env_flags_vartype_string; +} + +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) +{ +	char *access; + +	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) +		return env_flags_varaccess_any; + +	access = strchr(env_flags_varaccess_rep, +		flags[ENV_FLAGS_VARACCESS_LOC]); + +	if (access != NULL) +		return (enum env_flags_varaccess) +			(access - &env_flags_varaccess_rep[0]); + +	printf("## Warning: Unknown environment variable access method '%c'\n", +		flags[ENV_FLAGS_VARACCESS_LOC]); +	return env_flags_varaccess_any; +} + +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) +{ +	int i; + +	for (i = 0; i < sizeof(env_flags_varaccess_mask); i++) +		if (env_flags_varaccess_mask[i] == +		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) +			return (enum env_flags_varaccess)i; + +	printf("Warning: Non-standard access flags. (0x%x)\n", +		binflags & ENV_FLAGS_VARACCESS_BIN_MASK); + +	return env_flags_varaccess_any; +} + +static inline int is_hex_prefix(const char *value) +{ +	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); +} + +static void skip_num(int hex, const char *value, const char **end, +	int max_digits) +{ +	int i; + +	if (hex && is_hex_prefix(value)) +		value += 2; + +	for (i = max_digits; i != 0; i--) { +		if (hex && !isxdigit(*value)) +			break; +		if (!hex && !isdigit(*value)) +			break; +		value++; +	} +	if (end != NULL) +		*end = value; +} + +/* + * Based on the declared type enum, validate that the value string complies + * with that format + */ +static int _env_flags_validate_type(const char *value, +	enum env_flags_vartype type) +{ +	const char *end; +#ifdef CONFIG_CMD_NET +	const char *cur; +	int i; +#endif + +	switch (type) { +	case env_flags_vartype_string: +		break; +	case env_flags_vartype_decimal: +		skip_num(0, value, &end, -1); +		if (*end != '\0') +			return -1; +		break; +	case env_flags_vartype_hex: +		skip_num(1, value, &end, -1); +		if (*end != '\0') +			return -1; +		if (value + 2 == end && is_hex_prefix(value)) +			return -1; +		break; +	case env_flags_vartype_bool: +		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && +		    value[0] != 'Y' && value[0] != 'T' && +		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' && +		    value[0] != 'N' && value[0] != 'F') +			return -1; +		if (value[1] != '\0') +			return -1; +		break; +#ifdef CONFIG_CMD_NET +	case env_flags_vartype_ipaddr: +		cur = value; +		for (i = 0; i < 4; i++) { +			skip_num(0, cur, &end, 3); +			if (cur == end) +				return -1; +			if (i != 3 && *end != '.') +				return -1; +			if (i == 3 && *end != '\0') +				return -1; +			cur = end + 1; +		} +		break; +	case env_flags_vartype_macaddr: +		cur = value; +		for (i = 0; i < 6; i++) { +			skip_num(1, cur, &end, 2); +			if (cur == end) +				return -1; +			if (cur + 2 == end && is_hex_prefix(cur)) +				return -1; +			if (i != 5 && *end != ':') +				return -1; +			if (i == 5 && *end != '\0') +				return -1; +			cur = end + 1; +		} +		break; +#endif +	case env_flags_vartype_end: +		return -1; +	} + +	/* OK */ +	return 0; +} + +/* + * Look for flags in a provided list and failing that the static list + */ +static inline int env_flags_lookup(const char *flags_list, const char *name, +	char *flags) +{ +	int ret = 1; + +	if (!flags) +		/* bad parameter */ +		return -1; + +	/* try the env first */ +	if (flags_list) +		ret = env_attr_lookup(flags_list, name, flags); + +	if (ret != 0) +		/* if not found in the env, look in the static list */ +		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); + +	return ret; +} + +#ifdef USE_HOSTCC /* Functions only used from tools/env */ +/* + * Look up any flags directly from the .flags variable and the static list + * and convert them to the vartype enum. + */ +enum env_flags_vartype env_flags_get_type(const char *name) +{ +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + +	if (env_flags_lookup(flags_list, name, flags)) +		return env_flags_vartype_string; + +	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) +		return env_flags_vartype_string; + +	return env_flags_parse_vartype(flags); +} + +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_varaccess(const char *name) +{ +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + +	if (env_flags_lookup(flags_list, name, flags)) +		return env_flags_varaccess_any; + +	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) +		return env_flags_varaccess_any; + +	return env_flags_parse_varaccess(flags); +} + +/* + * Validate that the proposed new value for "name" is valid according to the + * defined flags for that variable, if any. + */ +int env_flags_validate_type(const char *name, const char *value) +{ +	enum env_flags_vartype type; + +	if (value == NULL) +		return 0; +	type = env_flags_get_type(name); +	if (_env_flags_validate_type(value, type) < 0) { +		printf("## Error: flags type check failure for " +			"\"%s\" <= \"%s\" (type: %c)\n", +			name, value, env_flags_vartype_rep[type]); +		return -1; +	} +	return 0; +} + +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask) +{ +	enum env_flags_varaccess access; +	int access_mask; + +	access = env_flags_get_varaccess(name); +	access_mask = env_flags_varaccess_mask[access]; + +	return (check_mask & access_mask) != 0; +} + +/* + * Validate the parameters to "env set" directly + */ +int env_flags_validate_env_set_params(int argc, char * const argv[]) +{ +	if ((argc >= 3) && argv[2] != NULL) { +		enum env_flags_vartype type = env_flags_get_type(argv[1]); + +		/* +		 * we don't currently check types that need more than +		 * one argument +		 */ +		if (type != env_flags_vartype_string && argc > 3) { +			printf("## Error: too many parameters for setting " +				"\"%s\"\n", argv[1]); +			return -1; +		} +		return env_flags_validate_type(argv[1], argv[2]); +	} +	/* ok */ +	return 0; +} + +#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */ + +/* + * Parse the flag charachters from the .flags attribute list into the binary + * form to be stored in the environment entry->flags field. + */ +static int env_parse_flags_to_bin(const char *flags) +{ +	int binflags; + +	binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; +	binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)]; + +	return binflags; +} + +/* + * Look for possible flags for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_flags_init(ENTRY *var_entry) +{ +	const char *var_name = var_entry->key; +	const char *flags_list = getenv(ENV_FLAGS_VAR); +	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; +	int ret = 1; + +	/* look in the ".flags" and static for a reference to this variable */ +	ret = env_flags_lookup(flags_list, var_name, flags); + +	/* if any flags were found, set the binary form to the entry */ +	if (!ret && strlen(flags)) +		var_entry->flags = env_parse_flags_to_bin(flags); +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a flag in the flag list should remove its flags. + */ +static int clear_flags(ENTRY *entry) +{ +	entry->flags = 0; + +	return 0; +} + +/* + * Call for each element in the list that defines flags for a variable + */ +static int set_flags(const char *name, const char *value) +{ +	ENTRY e, *ep; + +	e.key	= name; +	e.data	= NULL; +	hsearch_r(e, FIND, &ep, &env_htab, 0); + +	/* does the env variable actually exist? */ +	if (ep != NULL) { +		/* the flag list is empty, so clear the flags */ +		if (value == NULL || strlen(value) == 0) +			ep->flags = 0; +		else +			/* assign the requested flags */ +			ep->flags = env_parse_flags_to_bin(value); +	} + +	return 0; +} + +static int on_flags(const char *name, const char *value, enum env_op op, +	int flags) +{ +	/* remove all flags */ +	hwalk_r(&env_htab, clear_flags); + +	/* configure any static flags */ +	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); +	/* configure any dynamic flags */ +	env_attr_walk(value, set_flags); + +	return 0; +} +U_BOOT_ENV_CALLBACK(flags, on_flags); + +/* + * Perform consistency checking before creating, overwriting, or deleting an + * environment variable. Called as a callback function by hsearch_r() and + * hdelete_r(). Returns 0 in case of success, 1 in case of failure. + * When (flag & H_FORCE) is set, do not print out any error message and force + * overwriting of write-once variables. + */ + +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, +	int flag) +{ +	const char *name; +	const char *oldval = NULL; + +	if (op != env_op_create) +		oldval = item->data; + +	name = item->key; + +	/* Default value for NULL to protect string-manipulating functions */ +	newval = newval ? : ""; + +	/* validate the value to match the variable type */ +	if (op != env_op_delete) { +		enum env_flags_vartype type = (enum env_flags_vartype) +			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); + +		if (_env_flags_validate_type(newval, type) < 0) { +			printf("## Error: flags type check failure for " +				"\"%s\" <= \"%s\" (type: %c)\n", +				name, newval, env_flags_vartype_rep[type]); +			return -1; +		} +	} + +	/* check for access permission */ +#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE +	if (flag & H_FORCE) +		return 0; +#endif +	switch (op) { +	case env_op_delete: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { +			printf("## Error: Can't delete \"%s\"\n", name); +			return 1; +		} +		break; +	case env_op_overwrite: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { +			printf("## Error: Can't overwrite \"%s\"\n", name); +			return 1; +		} else if (item->flags & +		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { +			const char *defval = getenv_default(name); + +			if (defval == NULL) +				defval = ""; +			printf("oldval: %s  defval: %s\n", oldval, defval); +			if (strcmp(oldval, defval) != 0) { +				printf("## Error: Can't overwrite \"%s\"\n", +					name); +				return 1; +			} +		} +		break; +	case env_op_create: +		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { +			printf("## Error: Can't create \"%s\"\n", name); +			return 1; +		} +		break; +	} + +	return 0; +} + +#endif diff --git a/common/env_flash.c b/common/env_flash.c index aa970d440..e07d336a4 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -142,7 +142,7 @@ int saveenv(void)  		goto done;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; @@ -275,7 +275,7 @@ int saveenv(void)  		goto done;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; diff --git a/common/env_mmc.c b/common/env_mmc.c index a2ff90bf4..ce2167121 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -130,7 +130,7 @@ int saveenv(void)  	}  	res = (char *)&env_new->data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		ret = 1; diff --git a/common/env_nand.c b/common/env_nand.c index 79e803370..22e72a20b 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -186,7 +186,7 @@ int saveenv(void)  		return 1;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -239,7 +239,7 @@ int saveenv(void)  		return 1;  	res = (char *)&env_new->data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_nvram.c b/common/env_nvram.c index 6483db39d..eab0e7be0 100644 --- a/common/env_nvram.c +++ b/common/env_nvram.c @@ -90,7 +90,7 @@ int saveenv(void)  	int	rcode = 0;  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_onenand.c b/common/env_onenand.c index da3507125..faa903d2f 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -95,7 +95,7 @@ int saveenv(void)  	};  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; diff --git a/common/env_sf.c b/common/env_sf.c index bbd472fcf..d9e908546 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -79,7 +79,7 @@ int saveenv(void)  	}  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1; @@ -277,7 +277,7 @@ int saveenv(void)  	}  	res = (char *)&env_new.data; -	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); +	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		goto done; diff --git a/common/fdt_support.c b/common/fdt_support.c index 963ea9023..6b9fa0550 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1315,7 +1315,7 @@ int fdt_set_status_by_alias(void *fdt, const char* alias,  	return fdt_set_node_status(fdt, offset, status, error_code);  } -#if defined(CONFIG_VIDEO) +#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD)  int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)  {  	int noff; diff --git a/common/hash.c b/common/hash.c new file mode 100644 index 000000000..e3a6e438a --- /dev/null +++ b/common/hash.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <hash.h> +#include <sha1.h> +#include <sha256.h> + +/* + * These are the hash algorithms we support. Chips which support accelerated + * crypto could perhaps add named version of these algorithms here. + */ +static struct hash_algo hash_algo[] = { +#ifdef CONFIG_SHA1 +	{ +		"SHA1", +		SHA1_SUM_LEN, +		sha1_csum_wd, +		CHUNKSZ_SHA1, +	}, +#endif +#ifdef CONFIG_SHA256 +	{ +		"SHA256", +		SHA256_SUM_LEN, +		sha256_csum_wd, +		CHUNKSZ_SHA256, +	}, +#endif +}; + +/** + * store_result: Store the resulting sum to an address or variable + * + * @algo:		Hash algorithm being used + * @sum:		Hash digest (algo->digest_size bytes) + * @dest:		Destination, interpreted as a hex address if it starts + *			with * or otherwise as an environment variable. + */ +static void store_result(struct hash_algo *algo, const u8 *sum, +			 const char *dest) +{ +	unsigned int i; + +	if (*dest == '*') { +		u8 *ptr; + +		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); +		memcpy(ptr, sum, algo->digest_size); +	} else { +		char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; +		char *str_ptr = str_output; + +		for (i = 0; i < algo->digest_size; i++) { +			sprintf(str_ptr, "%02x", sum[i]); +			str_ptr += 2; +		} +		str_ptr = '\0'; +		setenv(dest, str_output); +	} +} + +/** + * parse_verify_sum: Parse a hash verification parameter + * + * @algo:		Hash algorithm being used + * @verify_str:		Argument to parse. If it starts with * then it is + *			interpreted as a hex address containing the hash. + *			If the length is exactly the right number of hex digits + *			for the digest size, then we assume it is a hex digest. + *			Otherwise we assume it is an environment variable, and + *			look up its value (it must contain a hex digest). + * @vsum:		Returns binary digest value (algo->digest_size bytes) + * @return 0 if ok, non-zero on error + */ +static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum) +{ +	if (*verify_str == '*') { +		u8 *ptr; + +		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); +		memcpy(vsum, ptr, algo->digest_size); +	} else { +		unsigned int i; +		char *vsum_str; +		int digits = algo->digest_size * 2; + +		/* +		 * As with the original code from sha1sum.c, we assume that a +		 * string which matches the digest size exactly is a hex +		 * string and not an environment variable. +		 */ +		if (strlen(verify_str) == digits) +			vsum_str = verify_str; +		else { +			vsum_str = getenv(verify_str); +			if (vsum_str == NULL || strlen(vsum_str) != digits) { +				printf("Expected %d hex digits in env var\n", +				       digits); +				return 1; +			} +		} + +		for (i = 0; i < algo->digest_size; i++) { +			char *nullp = vsum_str + (i + 1) * 2; +			char end = *nullp; + +			*nullp = '\0'; +			vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); +			*nullp = end; +		} +	} +	return 0; +} + +static struct hash_algo *find_hash_algo(const char *name) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { +		if (!strcasecmp(name, hash_algo[i].name)) +			return &hash_algo[i]; +	} + +	return NULL; +} + +static void show_hash(struct hash_algo *algo, ulong addr, ulong len, +		      u8 *output) +{ +	int i; + +	printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); +	for (i = 0; i < algo->digest_size; i++) +		printf("%02x", output[i]); +} + +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, +		 int argc, char * const argv[]) +{ +	struct hash_algo *algo; +	ulong addr, len; +	u8 output[HASH_MAX_DIGEST_SIZE]; +	u8 vsum[HASH_MAX_DIGEST_SIZE]; + +	if (argc < 2) +		return CMD_RET_USAGE; + +	algo = find_hash_algo(algo_name); +	if (!algo) { +		printf("Unknown hash algorithm '%s'\n", algo_name); +		return CMD_RET_USAGE; +	} +	addr = simple_strtoul(*argv++, NULL, 16); +	len = simple_strtoul(*argv++, NULL, 16); +	argc -= 2; + +	if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { +		puts("HASH_MAX_DIGEST_SIZE exceeded\n"); +		return 1; +	} + +	algo->hash_func_ws((const unsigned char *)addr, len, output, +			   algo->chunk_size); + +	/* Try to avoid code bloat when verify is not needed */ +#ifdef CONFIG_HASH_VERIFY +	if (verify) { +#else +	if (0) { +#endif +		if (!argc) +			return CMD_RET_USAGE; +		if (parse_verify_sum(algo, *argv, vsum)) { +			printf("ERROR: %s does not contain a valid %s sum\n", +				*argv, algo->name); +			return 1; +		} +		if (memcmp(output, vsum, algo->digest_size) != 0) { +			int i; + +			show_hash(algo, addr, len, output); +			printf(" != "); +			for (i = 0; i < algo->digest_size; i++) +				printf("%02x", vsum[i]); +			puts(" ** ERROR **\n"); +			return 1; +		} +	} else { +		show_hash(algo, addr, len, output); +		printf("\n"); + +		if (argc) +			store_result(algo, output, *argv); +	} + +	return 0; +} diff --git a/common/image.c b/common/image.c index df642e656..95498e618 100644 --- a/common/image.c +++ b/common/image.c @@ -43,6 +43,7 @@  #include <rtc.h>  #endif +#include <environment.h>  #include <image.h>  #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) @@ -416,11 +417,25 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,  /* Shared dual-format routines */  /*****************************************************************************/  #ifndef USE_HOSTCC -int getenv_yesno(char *var) +ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */ +ulong save_addr;			/* Default Save Address */ +ulong save_size;			/* Default Save Size (in bytes) */ + +static int on_loadaddr(const char *name, const char *value, enum env_op op, +	int flags)  { -	char *s = getenv(var); -	return (s && (*s == 'n')) ? 0 : 1; +	switch (op) { +	case env_op_create: +	case env_op_overwrite: +		load_addr = simple_strtoul(value, NULL, 16); +		break; +	default: +		break; +	} + +	return 0;  } +U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);  ulong getenv_bootm_low(void)  { @@ -3049,6 +3064,133 @@ int fit_check_format(const void *fit)  	return 1;  } + +/** + * fit_conf_find_compat + * @fit: pointer to the FIT format image header + * @fdt: pointer to the device tree to compare against + * + * fit_conf_find_compat() attempts to find the configuration whose fdt is the + * most compatible with the passed in device tree. + * + * Example: + * + * / o image-tree + *   |-o images + *   | |-o fdt@1 + *   | |-o fdt@2 + *   | + *   |-o configurations + *     |-o config@1 + *     | |-fdt = fdt@1 + *     | + *     |-o config@2 + *       |-fdt = fdt@2 + * + * / o U-Boot fdt + *   |-compatible = "foo,bar", "bim,bam" + * + * / o kernel fdt1 + *   |-compatible = "foo,bar", + * + * / o kernel fdt2 + *   |-compatible = "bim,bam", "baz,biz" + * + * Configuration 1 would be picked because the first string in U-Boot's + * compatible list, "foo,bar", matches a compatible string in the root of fdt1. + * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1. + * + * returns: + *     offset to the configuration to use if one was found + *     -1 otherwise + */ +int fit_conf_find_compat(const void *fit, const void *fdt) +{ +	int ndepth = 0; +	int noffset, confs_noffset, images_noffset; +	const void *fdt_compat; +	int fdt_compat_len; +	int best_match_offset = 0; +	int best_match_pos = 0; + +	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); +	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); +	if (confs_noffset < 0 || images_noffset < 0) { +		debug("Can't find configurations or images nodes.\n"); +		return -1; +	} + +	fdt_compat = fdt_getprop(fdt, 0, "compatible", &fdt_compat_len); +	if (!fdt_compat) { +		debug("Fdt for comparison has no \"compatible\" property.\n"); +		return -1; +	} + +	/* +	 * Loop over the configurations in the FIT image. +	 */ +	for (noffset = fdt_next_node(fit, confs_noffset, &ndepth); +			(noffset >= 0) && (ndepth > 0); +			noffset = fdt_next_node(fit, noffset, &ndepth)) { +		const void *kfdt; +		const char *kfdt_name; +		int kfdt_noffset; +		const char *cur_fdt_compat; +		int len; +		size_t size; +		int i; + +		if (ndepth > 1) +			continue; + +		kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); +		if (!kfdt_name) { +			debug("No fdt property found.\n"); +			continue; +		} +		kfdt_noffset = fdt_subnode_offset(fit, images_noffset, +						  kfdt_name); +		if (kfdt_noffset < 0) { +			debug("No image node named \"%s\" found.\n", +			      kfdt_name); +			continue; +		} +		/* +		 * Get a pointer to this configuration's fdt. +		 */ +		if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) { +			debug("Failed to get fdt \"%s\".\n", kfdt_name); +			continue; +		} + +		len = fdt_compat_len; +		cur_fdt_compat = fdt_compat; +		/* +		 * Look for a match for each U-Boot compatibility string in +		 * turn in this configuration's fdt. +		 */ +		for (i = 0; len > 0 && +		     (!best_match_offset || best_match_pos > i); i++) { +			int cur_len = strlen(cur_fdt_compat) + 1; + +			if (!fdt_node_check_compatible(kfdt, 0, +						       cur_fdt_compat)) { +				best_match_offset = noffset; +				best_match_pos = i; +				break; +			} +			len -= cur_len; +			cur_fdt_compat += cur_len; +		} +	} +	if (!best_match_offset) { +		debug("No match found.\n"); +		return -1; +	} + +	return best_match_offset; +} +  /**   * fit_conf_get_node - get node offset for configuration of a given unit name   * @fit: pointer to the FIT format image header diff --git a/common/lcd.c b/common/lcd.c index 301760473..4778655a2 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -696,6 +696,138 @@ static void splash_align_axis(int *axis, unsigned long panel_size,  }  #endif + +#ifdef CONFIG_LCD_BMP_RLE8 + +#define BMP_RLE8_ESCAPE		0 +#define BMP_RLE8_EOL		0 +#define BMP_RLE8_EOBMP		1 +#define BMP_RLE8_DELTA		2 + +static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap, +				  int cnt) +{ +	while (cnt > 0) { +		*(*fbp)++ = cmap[*bmap++]; +		cnt--; +	} +} + +static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) +{ +	ushort *fb = *fbp; +	int cnt_8copy = cnt >> 3; + +	cnt -= cnt_8copy << 3; +	while (cnt_8copy > 0) { +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		*fb++ = c; +		cnt_8copy--; +	} +	while (cnt > 0) { +		*fb++ = c; +		cnt--; +	} +	(*fbp) = fb; +} + +/* + * Do not call this function directly, must be called from + * lcd_display_bitmap. + */ +static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb, +				    int x_off, int y_off) +{ +	uchar *bmap; +	ulong width, height; +	ulong cnt, runlen; +	int x, y; +	int decode = 1; + +	width = le32_to_cpu(bmp->header.width); +	height = le32_to_cpu(bmp->header.height); +	bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset); + +	x = 0; +	y = height - 1; + +	while (decode) { +		if (bmap[0] == BMP_RLE8_ESCAPE) { +			switch (bmap[1]) { +			case BMP_RLE8_EOL: +				/* end of line */ +				bmap += 2; +				x = 0; +				y--; +				/* 16bpix, 2-byte per pixel, width should *2 */ +				fb -= (width * 2 + lcd_line_length); +				break; +			case BMP_RLE8_EOBMP: +				/* end of bitmap */ +				decode = 0; +				break; +			case BMP_RLE8_DELTA: +				/* delta run */ +				x += bmap[2]; +				y -= bmap[3]; +				/* 16bpix, 2-byte per pixel, x should *2 */ +				fb = (uchar *) (lcd_base + (y + y_off - 1) +					* lcd_line_length + (x + x_off) * 2); +				bmap += 4; +				break; +			default: +				/* unencoded run */ +				runlen = bmap[1]; +				bmap += 2; +				if (y < height) { +					if (x < width) { +						if (x + runlen > width) +							cnt = width - x; +						else +							cnt = runlen; +						draw_unencoded_bitmap( +							(ushort **)&fb, +							bmap, cmap, cnt); +					} +					x += runlen; +				} +				bmap += runlen; +				if (runlen & 1) +					bmap++; +			} +		} else { +			/* encoded run */ +			if (y < height) { +				runlen = bmap[0]; +				if (x < width) { +					/* aggregate the same code */ +					while (bmap[0] == 0xff && +					       bmap[2] != BMP_RLE8_ESCAPE && +					       bmap[1] == bmap[3]) { +						runlen += bmap[2]; +						bmap += 2; +					} +					if (x + runlen > width) +						cnt = width - x; +					else +						cnt = runlen; +					draw_encoded_bitmap((ushort **)&fb, +						cmap[bmap[1]], cnt); +				} +				x += runlen; +			} +			bmap += 2; +		} +	} +} +#endif +  #if defined(CONFIG_MPC823) || defined(CONFIG_MCC200)  #define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++)  #else @@ -729,7 +861,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	uchar *fb;  	bmp_image_t *bmp=(bmp_image_t *)bmp_image;  	uchar *bmap; -	ushort padded_line; +	ushort padded_width;  	unsigned long width, height, byte_width;  	unsigned long pwidth = panel_info.vl_col;  	unsigned colors, bpix, bmp_bpix; @@ -816,7 +948,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	}  #endif -	padded_line = (width&0x3) ? ((width&~0x3)+4) : (width); +	padded_width = (width&0x3) ? ((width&~0x3)+4) : (width);  #ifdef CONFIG_SPLASH_SCREEN_ALIGN  	splash_align_axis(&x, pwidth, width); @@ -835,6 +967,18 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  	switch (bmp_bpix) {  	case 1: /* pass through */  	case 8: +#ifdef CONFIG_LCD_BMP_RLE8 +		if (le32_to_cpu(bmp->header.compression) == BMP_BI_RLE8) { +			if (bpix != 16) { +				/* TODO implement render code for bpix != 16 */ +				printf("Error: only support 16 bpix"); +				return 1; +			} +			lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y); +			break; +		} +#endif +  		if (bpix != 16)  			byte_width = width;  		else @@ -850,7 +994,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  					fb += sizeof(uint16_t) / sizeof(*fb);  				}  			} -			bmap += (width - padded_line); +			bmap += (padded_width - width);  			fb   -= (byte_width + lcd_line_length);  		}  		break; @@ -862,7 +1006,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)  			for (j = 0; j < width; j++)  				fb_put_word(&fb, &bmap); -			bmap += (padded_line - width) * 2; +			bmap += (padded_width - width) * 2;  			fb   -= (width * 2 + lcd_line_length);  		}  		break; @@ -940,5 +1084,31 @@ static void *lcd_logo(void)  #endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */  } +void lcd_position_cursor(unsigned col, unsigned row) +{ +	console_col = min(col, CONSOLE_COLS - 1); +	console_row = min(row, CONSOLE_ROWS - 1); +} + +int lcd_get_pixel_width(void) +{ +	return panel_info.vl_col; +} + +int lcd_get_pixel_height(void) +{ +	return panel_info.vl_row; +} + +int lcd_get_screen_rows(void) +{ +	return CONSOLE_ROWS; +} + +int lcd_get_screen_columns(void) +{ +	return CONSOLE_COLS; +} +  /************************************************************************/  /************************************************************************/ diff --git a/common/main.c b/common/main.c index 5fdfff2e2..5d8454ea0 100644 --- a/common/main.c +++ b/common/main.c @@ -30,6 +30,7 @@  #include <common.h>  #include <watchdog.h>  #include <command.h> +#include <fdtdec.h>  #include <malloc.h>  #include <version.h>  #ifdef CONFIG_MODEM_SUPPORT @@ -40,13 +41,19 @@  #include <hush.h>  #endif +#ifdef CONFIG_OF_CONTROL +#include <fdtdec.h> +#endif + +#ifdef CONFIG_OF_LIBFDT +#include <fdt_support.h> +#endif /* CONFIG_OF_LIBFDT */ +  #include <post.h>  #include <linux/ctype.h>  #include <menu.h> -#if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING)  DECLARE_GLOBAL_DATA_PTR; -#endif  /*   * Board-specific Platform code can reimplement show_boot_progress () if needed @@ -274,6 +281,73 @@ int abortboot(int bootdelay)  # endif	/* CONFIG_AUTOBOOT_KEYED */  #endif	/* CONFIG_BOOTDELAY >= 0  */ +/* + * Runs the given boot command securely.  Specifically: + * - Doesn't run the command with the shell (run_command or parse_string_outer), + *   since that's a lot of code surface that an attacker might exploit. + *   Because of this, we don't do any argument parsing--the secure boot command + *   has to be a full-fledged u-boot command. + * - Doesn't check for keypresses before booting, since that could be a + *   security hole; also disables Ctrl-C. + * - Doesn't allow the command to return. + * + * Upon any failures, this function will drop into an infinite loop after + * printing the error message to console. + */ + +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ +	defined(CONFIG_OF_CONTROL) +static void secure_boot_cmd(char *cmd) +{ +	cmd_tbl_t *cmdtp; +	int rc; + +	if (!cmd) { +		printf("## Error: Secure boot command not specified\n"); +		goto err; +	} + +	/* Disable Ctrl-C just in case some command is used that checks it. */ +	disable_ctrlc(1); + +	/* Find the command directly. */ +	cmdtp = find_cmd(cmd); +	if (!cmdtp) { +		printf("## Error: \"%s\" not defined\n", cmd); +		goto err; +	} + +	/* Run the command, forcing no flags and faking argc and argv. */ +	rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd); + +	/* Shouldn't ever return from boot command. */ +	printf("## Error: \"%s\" returned (code %d)\n", cmd, rc); + +err: +	/* +	 * Not a whole lot to do here.  Rebooting won't help much, since we'll +	 * just end up right back here.  Just loop. +	 */ +	hang(); +} + +static void process_fdt_options(const void *blob) +{ +	ulong addr; + +	/* Add an env variable to point to a kernel payload, if available */ +	addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0); +	if (addr) +		setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); + +	/* Add an env variable to point to a root disk, if available */ +	addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0); +	if (addr) +		setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr)); +} +#endif /* CONFIG_OF_CONTROL */ + +  /****************************************************************************/  void main_loop (void) @@ -284,7 +358,10 @@ void main_loop (void)  	int rc = 1;  	int flag;  #endif - +#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) && \ +		defined(CONFIG_OF_CONTROL) +	char *env; +#endif  #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)  	char *s;  	int bootdelay; @@ -299,6 +376,8 @@ void main_loop (void)  	char bcs_set[16];  #endif /* CONFIG_BOOTCOUNT_LIMIT */ +	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); +  #ifdef CONFIG_BOOTCOUNT_LIMIT  	bootcount = bootcount_load();  	bootcount++; @@ -380,6 +459,23 @@ void main_loop (void)  	else  #endif /* CONFIG_BOOTCOUNT_LIMIT */  		s = getenv ("bootcmd"); +#ifdef CONFIG_OF_CONTROL +	/* Allow the fdt to override the boot command */ +	env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd"); +	if (env) +		s = env; + +	process_fdt_options(gd->fdt_blob); + +	/* +	 * If the bootsecure option was chosen, use secure_boot_cmd(). +	 * Always use 'env' in this case, since bootsecure requres that the +	 * bootcmd was specified in the FDT too. +	 */ +	if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0)) +		secure_boot_cmd(env); + +#endif /* CONFIG_OF_CONTROL */  	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); @@ -404,6 +500,10 @@ void main_loop (void)  #endif /* CONFIG_MENUKEY */  #endif /* CONFIG_BOOTDELAY */ +#if defined CONFIG_OF_CONTROL +	set_working_fdt_addr((void *)gd->fdt_blob); +#endif /* CONFIG_OF_CONTROL */ +  	/*  	 * Main Loop for Monitor Command Processing  	 */ diff --git a/common/spl/spl.c b/common/spl/spl.c index f068abd8f..ff9ba7b0a 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -74,6 +74,16 @@ __weak int spl_start_uboot(void)  }  #endif +/* + * Weak default function for board specific cleanup/preparation before + * Linux boot. Some boards/platforms might not need it, so just provide + * an empty stub here. + */ +__weak void spl_board_prepare_for_linux(void) +{ +	/* Nothing to do! */ +} +  void spl_parse_image_header(const struct image_header *header)  {  	u32 header_size = sizeof(struct image_header); @@ -155,7 +165,13 @@ void board_init_r(gd_t *dummy1, ulong dummy2)  			CONFIG_SYS_SPL_MALLOC_SIZE);  #endif +#ifndef CONFIG_PPC +	/* +	 * timer_init() does not exist on PPC systems. The timer is initialized +	 * and enabled (decrementer) in interrupt_init() here. +	 */  	timer_init(); +#endif  #ifdef CONFIG_SPL_BOARD_INIT  	spl_board_init(); diff --git a/common/stdio.c b/common/stdio.c index 605ff3fde..97ff9cf4a 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -135,7 +135,6 @@ struct stdio_dev* stdio_clone(struct stdio_dev *dev)  		return NULL;  	memcpy(_dev, dev, sizeof(struct stdio_dev)); -	strncpy(_dev->name, dev->name, 16);  	return _dev;  } @@ -237,6 +236,8 @@ int stdio_init (void)  #ifdef CONFIG_JTAG_CONSOLE  	drv_jtag_console_init ();  #endif - +#ifdef CONFIG_CBMEM_CONSOLE +	cbmemc_init(); +#endif  	return (0);  } diff --git a/common/usb.c b/common/usb.c index 50b81752e..ac9b4ca8d 100644 --- a/common/usb.c +++ b/common/usb.c @@ -492,9 +492,9 @@ int usb_get_configuration_no(struct usb_device *dev,  {  	int result;  	unsigned int tmp; -	struct usb_configuration_descriptor *config; +	struct usb_config_descriptor *config; -	config = (struct usb_configuration_descriptor *)&buffer[0]; +	config = (struct usb_config_descriptor *)&buffer[0];  	result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9);  	if (result < 9) {  		if (result < 0) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index 19f01db1c..4efbcfe90 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -94,6 +94,15 @@ static const unsigned char usb_kbd_num_keypad[] = {  };  /* + * map arrow keys to ^F/^B ^N/^P, can't really use the proper + * ANSI sequence for arrow keys because the queuing code breaks + * when a single keypress expands to 3 queue elements + */ +static const unsigned char usb_kbd_arrow[] = { +	0x6, 0x2, 0xe, 0x10 +}; + +/*   * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this   *       order. See usb_kbd_setled() function!   */ @@ -112,7 +121,7 @@ struct usb_kbd_pdata {  	uint32_t	usb_out_pointer;  	uint8_t		usb_kbd_buffer[USB_KBD_BUFFER_LEN]; -	uint8_t		new[8]; +	uint8_t		*new;  	uint8_t		old[8];  	uint8_t		flags; @@ -224,6 +233,10 @@ static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,  			keycode = usb_kbd_numkey[scancode - 0x1e];  	} +	/* Arrow keys */ +	if ((scancode >= 0x4f) && (scancode <= 0x52)) +		keycode = usb_kbd_arrow[scancode - 0x4f]; +  	/* Numeric keypad */  	if ((scancode >= 0x54) && (scancode <= 0x67))  		keycode = usb_kbd_num_keypad[scancode - 0x54]; @@ -435,6 +448,9 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)  	/* Clear private data */  	memset(data, 0, sizeof(struct usb_kbd_pdata)); +	/* allocate input buffer aligned and sized to USB DMA alignment */ +	data->new = memalign(USB_DMA_MINALIGN, roundup(8, USB_DMA_MINALIGN)); +  	/* Insert private data into USB device structure */  	dev->privptr = data; |