diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/Makefile | 46 | ||||
| -rw-r--r-- | common/board_f.c | 17 | ||||
| -rw-r--r-- | common/board_r.c | 11 | ||||
| -rw-r--r-- | common/bootstage.c | 26 | ||||
| -rw-r--r-- | common/cmd_bootm.c | 564 | ||||
| -rw-r--r-- | common/cmd_ide.c | 14 | ||||
| -rw-r--r-- | common/cmd_mem.c | 2 | ||||
| -rw-r--r-- | common/cmd_mmc.c | 109 | ||||
| -rw-r--r-- | common/cmd_pxe.c | 221 | ||||
| -rw-r--r-- | common/cmd_trace.c | 133 | ||||
| -rw-r--r-- | common/image-fdt.c | 13 | ||||
| -rw-r--r-- | common/image-fit.c | 83 | ||||
| -rw-r--r-- | common/image-sig.c | 422 | ||||
| -rw-r--r-- | common/image.c | 22 | ||||
| -rw-r--r-- | common/usb_storage.c | 8 | 
15 files changed, 1252 insertions, 439 deletions
diff --git a/common/Makefile b/common/Makefile index 3ba431626..48791b7ff 100644 --- a/common/Makefile +++ b/common/Makefile @@ -44,13 +44,11 @@ COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o  COBJS-y += cmd_boot.o  COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o  COBJS-y += cmd_help.o -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 @@ -171,6 +169,7 @@ COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o  COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o  COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o  COBJS-$(CONFIG_CMD_TIME) += cmd_time.o +COBJS-$(CONFIG_CMD_TRACE) += cmd_trace.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o  COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o  COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o @@ -191,14 +190,6 @@ COBJS-$(CONFIG_CMD_ZIP) += cmd_zip.o  COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o  # others -ifdef CONFIG_DDR_SPD -SPD := y -endif -ifdef CONFIG_SPD_EEPROM -SPD := y -endif -COBJS-$(SPD) += ddr_spd.o -COBJS-$(CONFIG_HWCONFIG) += hwconfig.o  COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o  COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o  COBJS-y += flash.o @@ -216,24 +207,43 @@ 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 +# environment +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_flags.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_callback.o +ifneq ($(CONFIG_SPL_NET_SUPPORT),y) +COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o +COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o +COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o +COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o +COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o +else +COBJS-y += env_nowhere.o +endif  endif +# core command +COBJS-y += cmd_nvedit.o +#environment +COBJS-y += env_common.o +#others +ifdef CONFIG_DDR_SPD +SPD := y +endif +ifdef CONFIG_SPD_EEPROM +SPD := y +endif +COBJS-$(SPD) += ddr_spd.o +COBJS-$(CONFIG_HWCONFIG) += hwconfig.o  COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o  COBJS-y += console.o  COBJS-y += dlmalloc.o  COBJS-y += image.o  COBJS-$(CONFIG_OF_LIBFDT) += image-fdt.o  COBJS-$(CONFIG_FIT) += image-fit.o +COBJS-$(CONFIG_FIT_SIGNATURE) += image-sig.o  COBJS-y += memsize.o  COBJS-y += stdio.o diff --git a/common/board_f.c b/common/board_f.c index 8efdb6365..ab4242a77 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -53,6 +53,7 @@  #include <os.h>  #include <post.h>  #include <spi.h> +#include <trace.h>  #include <watchdog.h>  #include <asm/errno.h>  #include <asm/io.h> @@ -500,6 +501,18 @@ static int reserve_lcd(void)  }  #endif /* CONFIG_LCD */ +static int reserve_trace(void) +{ +#ifdef CONFIG_TRACE +	gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE; +	gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE); +	debug("Reserving %dk for trace data at: %08lx\n", +	      CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr); +#endif + +	return 0; +} +  #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \  		&& !defined(CONFIG_ARM) && !defined(CONFIG_X86)  static int reserve_video(void) @@ -818,8 +831,9 @@ static init_fnc_t init_sequence_f[] = {  #ifdef CONFIG_SANDBOX  	setup_ram_buf,  #endif -	setup_fdt,  	setup_mon_len, +	setup_fdt, +	trace_early_init,  #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)  	/* TODO: can this go into arch_cpu_init()? */  	probecpu, @@ -963,6 +977,7 @@ static init_fnc_t init_sequence_f[] = {  #ifdef CONFIG_LCD  	reserve_lcd,  #endif +	reserve_trace,  	/* TODO: Why the dependency on CONFIG_8xx? */  #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \  		&& !defined(CONFIG_ARM) && !defined(CONFIG_X86) diff --git a/common/board_r.c b/common/board_r.c index f5649c95f..f7a036e32 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -58,6 +58,7 @@  #include <serial.h>  #include <spi.h>  #include <stdio_dev.h> +#include <trace.h>  #include <watchdog.h>  #ifdef CONFIG_ADDR_MAP  #include <asm/mmu.h> @@ -106,6 +107,15 @@ static int initr_secondary_cpu(void)  	return 0;  } +static int initr_trace(void) +{ +#ifdef CONFIG_TRACE +	trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE); +#endif + +	return 0; +} +  static int initr_reloc(void)  {  	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */ @@ -711,6 +721,7 @@ static int run_main_loop(void)   * TODO: perhaps reset the watchdog in the initcall function after each call?   */  init_fnc_t init_sequence_r[] = { +	initr_trace,  	initr_reloc,  	/* TODO: could x86/PPC have this also perhaps? */  #ifdef CONFIG_ARM diff --git a/common/bootstage.c b/common/bootstage.c index c5c69961a..94a32a997 100644 --- a/common/bootstage.c +++ b/common/bootstage.c @@ -49,6 +49,7 @@ static int next_id = BOOTSTAGE_ID_USER;  enum {  	BOOTSTAGE_VERSION	= 0,  	BOOTSTAGE_MAGIC		= 0xb00757a3, +	BOOTSTAGE_DIGITS	= 9,  };  struct bootstage_hdr { @@ -165,21 +166,6 @@ uint32_t bootstage_accum(enum bootstage_id id)  	return duration;  } -static void print_time(unsigned long us_time) -{ -	char str[15], *s; -	int grab = 3; - -	/* We don't seem to have %'d in U-Boot */ -	sprintf(str, "%12lu", us_time); -	for (s = str + 3; *s; s += grab) { -		if (s != str + 3) -			putc(s[-1] != ' ' ? ',' : ' '); -		printf("%.*s", grab, s); -		grab = 3; -	} -} -  /**   * Get a record name as a printable string   * @@ -208,10 +194,10 @@ static uint32_t print_time_record(enum bootstage_id id,  	if (prev == -1U) {  		printf("%11s", ""); -		print_time(rec->time_us); +		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);  	} else { -		print_time(rec->time_us); -		print_time(rec->time_us - prev); +		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); +		print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);  	}  	printf("  %s\n", get_record_name(buf, sizeof(buf), rec)); @@ -445,9 +431,9 @@ int bootstage_unstash(void *base, int size)  	}  	if (hdr->count * sizeof(*rec) > hdr->size) { -		debug("%s: Bootstage has %d records needing %d bytes, but " +		debug("%s: Bootstage has %d records needing %lu bytes, but "  			"only %d bytes is available\n", __func__, hdr->count, -		      hdr->count * sizeof(*rec), hdr->size); +		      (ulong)hdr->count * sizeof(*rec), hdr->size);  		return -1;  	} diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 05130b693..02a5013c0 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -104,9 +104,18 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,   *  - verified image architecture (PPC) and type (KERNEL or MULTI),   *  - loaded (first part of) image to header load address,   *  - disabled interrupts. + * + * @flag: Flags indicating what to do (BOOTM_STATE_...) + * @argc: Number of arguments. Note that the arguments are shifted down + *	 so that 0 is the first argument not processed by U-Boot, and + *	 argc is adjusted accordingly. This avoids confusion as to how + *	 many arguments are available for the OS. + * @images: Pointers to os/initrd/fdt + * @return 1 on error. On success the OS boots so this function does + * not return.   */  typedef int boot_os_fn(int flag, int argc, char * const argv[], -			bootm_headers_t *images); /* pointers to os/initrd/fdt */ +			bootm_headers_t *images);  #ifdef CONFIG_BOOTM_LINUX  extern boot_os_fn do_bootm_linux; @@ -199,15 +208,21 @@ static inline void boot_start_lmb(bootm_headers_t *images) { }  static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	const void *os_hdr; -	int ret; -  	memset((void *)&images, 0, sizeof(images));  	images.verify = getenv_yesno("verify");  	boot_start_lmb(&images);  	bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); +	images.state = BOOTM_STATE_START; + +	return 0; +} + +static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, +			 char * const argv[]) +{ +	const void *os_hdr;  	/* get kernel image header, start address and length */  	os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, @@ -270,6 +285,8 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  		images.ep = image_get_ep(&images.legacy_hdr_os_copy);  #if defined(CONFIG_FIT)  	} else if (images.fit_uname_os) { +		int ret; +  		ret = fit_image_get_entry(images.fit_hdr_os,  					  images.fit_noffset_os, &images.ep);  		if (ret) { @@ -287,6 +304,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  		images.ep += images.os.load;  	} +	images.os.start = (ulong)os_hdr; + +	return 0; +} + +static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, +			    char * const argv[]) +{ +	int ret; +  	if (((images.os.type == IH_TYPE_KERNEL) ||  	     (images.os.type == IH_TYPE_KERNEL_NOLOAD) ||  	     (images.os.type == IH_TYPE_MULTI)) && @@ -312,17 +339,16 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]  #endif  	} -	images.os.start = (ulong)os_hdr; -	images.state = BOOTM_STATE_START; -  	return 0;  }  #define BOOTM_ERR_RESET		-1  #define BOOTM_ERR_OVERLAP	-2  #define BOOTM_ERR_UNIMPLEMENTED	-3 -static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) +static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end, +		int boot_progress)  { +	image_info_t os = images->os;  	uint8_t comp = os.comp;  	ulong load = os.load;  	ulong blob_start = os.start; @@ -440,13 +466,23 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)  		debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,  			*load_end); -		return BOOTM_ERR_OVERLAP; +		/* Check what type of image this is. */ +		if (images->legacy_hdr_valid) { +			if (image_get_type(&images->legacy_hdr_os_copy) +					== IH_TYPE_MULTI) +				puts("WARNING: legacy format multi component image overwritten\n"); +			return BOOTM_ERR_OVERLAP; +		} else { +			puts("ERROR: new format image overwritten - must RESET the board to recover\n"); +			bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); +			return BOOTM_ERR_RESET; +		}  	}  	return 0;  } -static int bootm_start_standalone(ulong iflag, int argc, char * const argv[]) +static int bootm_start_standalone(int argc, char * const argv[])  {  	char  *s;  	int   (*appl)(int, char * const []); @@ -457,7 +493,7 @@ static int bootm_start_standalone(ulong iflag, int argc, char * const argv[])  		return 0;  	}  	appl = (int (*)(int, char * const []))(ulong)ntohl(images.ep); -	(*appl)(argc-1, &argv[1]); +	(*appl)(argc, argv);  	return 0;  } @@ -475,110 +511,227 @@ static cmd_tbl_t cmd_bootm_sub[] = {  	U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""),  	U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""),  	U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), +	U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""),  	U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""),  }; -static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, -			char * const argv[]) +static int boot_selected_os(int argc, char * const argv[], int state, +		bootm_headers_t *images, boot_os_fn *boot_fn) +{ +	if (images->os.type == IH_TYPE_STANDALONE) { +		/* This may return when 'autostart' is 'no' */ +		bootm_start_standalone(argc, argv); +		return 0; +	} +#ifdef CONFIG_SILENT_CONSOLE +	if (images->os.os == IH_OS_LINUX) +		fixup_silent_linux(); +#endif +	arch_preboot_os(); +	boot_fn(state, argc, argv, images); +	if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ +		return 0; +	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); +#ifdef DEBUG +	puts("\n## Control returned to monitor - resetting...\n"); +#endif +	return BOOTM_ERR_RESET; +} + +/** + * Execute selected states of the bootm command. + * + * Note the arguments to this state must be the first argument, Any 'bootm' + * or sub-command arguments must have already been taken. + * + * Note that if states contains more than one flag it MUST contain + * BOOTM_STATE_START, since this handles and consumes the command line args. + * + * Also note that aside from boot_os_fn functions and bootm_load_os no other + * functions we store the return value of in 'ret' may use a negative return + * value, without special handling. + * + * @param cmdtp		Pointer to bootm command table entry + * @param flag		Command flags (CMD_FLAG_...) + * @param argc		Number of subcommand arguments (0 = no arguments) + * @param argv		Arguments + * @param states	Mask containing states to run (BOOTM_STATE_...) + * @param images	Image header information + * @param boot_progress 1 to show boot progress, 0 to not do this + * @return 0 if ok, something else on error. Some errors will cause this + *	function to perform a reboot! If states contains BOOTM_STATE_OS_GO + *	then the intent is to boot an OS, so this function will not return + *	unless the image type is standalone. + */ +static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, +		char * const argv[], int states, bootm_headers_t *images, +		int boot_progress)  { -	int ret = 0; -	long state; -	cmd_tbl_t *c;  	boot_os_fn *boot_fn; +	ulong iflag = 0; +	int ret = 0; -	c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); +	images->state |= states; -	if (c) { -		state = (long)c->cmd; +	/* +	 * Work through the states and see how far we get. We stop on +	 * any error. +	 */ +	if (states & BOOTM_STATE_START) +		ret = bootm_start(cmdtp, flag, argc, argv); -		/* treat start special since it resets the state machine */ -		if (state == BOOTM_STATE_START) { -			argc--; -			argv++; -			return bootm_start(cmdtp, flag, argc, argv); -		} -	} else { -		/* Unrecognized command */ -		return CMD_RET_USAGE; -	} +	if (!ret && (states & BOOTM_STATE_FINDOS)) +		ret = bootm_find_os(cmdtp, flag, argc, argv); -	if (images.state < BOOTM_STATE_START || -	    images.state >= state) { -		printf("Trying to execute a command out of order\n"); -		return CMD_RET_USAGE; +	if (!ret && (states & BOOTM_STATE_FINDOTHER)) { +		ret = bootm_find_other(cmdtp, flag, argc, argv); +		argc = 0;	/* consume the args */  	} -	images.state |= state; -	boot_fn = boot_os[images.os.os]; +	/* +	 * We have reached the point of no return: we are going to +	 * overwrite all exception vector code, so we cannot easily +	 * recover from any failures any more... +	 */ +	iflag = disable_interrupts(); +#ifdef CONFIG_NETCONSOLE +	/* Stop the ethernet stack if NetConsole could have left it up */ +	eth_halt(); +#endif -	switch (state) { +#if defined(CONFIG_CMD_USB) +	/* +	 * turn off USB to prevent the host controller from writing to the +	 * SDRAM while Linux is booting. This could happen (at least for OHCI +	 * controller), because the HCCA (Host Controller Communication Area) +	 * lies within the SDRAM and the host controller writes continously to +	 * this area (as busmaster!). The HccaFrameNumber is for example +	 * updated every 1 ms within the HCCA structure in SDRAM! For more +	 * details see the OpenHCI specification. +	 */ +	usb_stop(); +#endif + +	/* Load the OS */ +	if (!ret && (states & BOOTM_STATE_LOADOS)) {  		ulong load_end; -		case BOOTM_STATE_START: -			/* should never occur */ -			break; -		case BOOTM_STATE_LOADOS: -			ret = bootm_load_os(images.os, &load_end, 0); -			if (ret) -				return ret; -			lmb_reserve(&images.lmb, images.os.load, -					(load_end - images.os.load)); -			break; -#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH -		case BOOTM_STATE_RAMDISK: -		{ -			ulong rd_len = images.rd_end - images.rd_start; +		ret = bootm_load_os(images, &load_end, 0); +		if (ret && ret != BOOTM_ERR_OVERLAP) +			goto err; + +		if (ret == 0) +			lmb_reserve(&images->lmb, images->os.load, +				    (load_end - images->os.load)); +		else if (ret == BOOTM_ERR_OVERLAP) +			ret = 0; +	} -			ret = boot_ramdisk_high(&images.lmb, images.rd_start, -				rd_len, &images.initrd_start, &images.initrd_end); -			if (ret) -				return ret; +	/* Relocate the ramdisk */ +#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH +	if (!ret && (states & BOOTM_STATE_RAMDISK)) { +		ulong rd_len = images->rd_end - images->rd_start; -			setenv_hex("initrd_start", images.initrd_start); -			setenv_hex("initrd_end", images.initrd_end); +		ret = boot_ramdisk_high(&images->lmb, images->rd_start, +			rd_len, &images->initrd_start, &images->initrd_end); +		if (!ret) { +			setenv_hex("initrd_start", images->initrd_start); +			setenv_hex("initrd_end", images->initrd_end);  		} -			break; +	}  #endif  #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) -		case BOOTM_STATE_FDT: -		{ -			boot_fdt_add_mem_rsv_regions(&images.lmb, -						     images.ft_addr); -			ret = boot_relocate_fdt(&images.lmb, -				&images.ft_addr, &images.ft_len); -			break; -		} +	if (!ret && (states & BOOTM_STATE_FDT)) { +		boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); +		ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, +					&images->ft_len); +	}  #endif -		case BOOTM_STATE_OS_CMDLINE: -			ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images); -			if (ret) -				printf("cmdline subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_BD_T: -			ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images); -			if (ret) -				printf("bdt subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_PREP: -			ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images); -			if (ret) -				printf("prep subcommand not supported\n"); -			break; -		case BOOTM_STATE_OS_GO: -			disable_interrupts(); -#ifdef CONFIG_NETCONSOLE -			/* -			 * Stop the ethernet stack if NetConsole could have -			 * left it up -			 */ -			eth_halt(); + +	/* From now on, we need the OS boot function */ +	if (ret) +		return ret; +	boot_fn = boot_os[images->os.os]; +	if (boot_fn == NULL) { +		if (iflag) +			enable_interrupts(); +		printf("ERROR: booting os '%s' (%d) is not supported\n", +		       genimg_get_os_name(images->os.os), images->os.os); +		bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); +		return 1; +	} + +	/* Call various other states that are not generally used */ +	if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) +		ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); +	if (!ret && (states & BOOTM_STATE_OS_BD_T)) +		ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); +	if (!ret && (states & BOOTM_STATE_OS_PREP)) +		ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); + +#ifdef CONFIG_TRACE +	/* Pretend to run the OS, then run a user command */ +	if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { +		char *cmd_list = getenv("fakegocmd"); + +		ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, +				images, boot_fn); +		if (!ret && cmd_list) +			ret = run_command_list(cmd_list, -1, flag); +	}  #endif -			arch_preboot_os(); -			boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images); -			break; +	/* Now run the OS! We hope this doesn't return */ +	if (!ret && (states & BOOTM_STATE_OS_GO)) { +		ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, +				images, boot_fn); +		if (ret) +			goto err;  	}  	return ret; + +	/* Deal with any fallout */ +err: +	if (iflag) +		enable_interrupts(); + +	if (ret == BOOTM_ERR_UNIMPLEMENTED) +		bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); +	else if (ret == BOOTM_ERR_RESET) +		do_reset(cmdtp, flag, argc, argv); +	else +		puts("subcommand not supported\n"); + +	return ret; +} + +static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, +			char * const argv[]) +{ +	int ret = 0; +	long state; +	cmd_tbl_t *c; + +	c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); +	argc--; argv++; + +	if (c) { +		state = (long)c->cmd; +		if (state == BOOTM_STATE_START) +			state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER; +	} else { +		/* Unrecognized command */ +		return CMD_RET_USAGE; +	} + +	if (state != BOOTM_STATE_START && images.state >= state) { +		printf("Trying to execute a command out of order\n"); +		return CMD_RET_USAGE; +	} + +	ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0); + +	return ret;  }  /*******************************************************************/ @@ -587,10 +740,6 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,  int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	ulong		iflag; -	ulong		load_end = 0; -	int		ret; -	boot_os_fn	*boot_fn;  #ifdef CONFIG_NEEDS_MANUAL_RELOC  	static int relocated = 0; @@ -611,11 +760,12 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  #endif  	/* determine if we have a sub command */ -	if (argc > 1) { +	argc--; argv++; +	if (argc > 0) {  		char *endp; -		simple_strtoul(argv[1], &endp, 16); -		/* endp pointing to NULL means that argv[1] was just a +		simple_strtoul(argv[0], &endp, 16); +		/* endp pointing to NULL means that argv[0] was just a  		 * valid number, pass it along to the normal bootm processing  		 *  		 * If endp is ':' or '#' assume a FIT identifier so pass @@ -627,101 +777,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  			return do_bootm_subcommand(cmdtp, flag, argc, argv);  	} -	if (bootm_start(cmdtp, flag, argc, argv)) -		return 1; - -	/* -	 * We have reached the point of no return: we are going to -	 * overwrite all exception vector code, so we cannot easily -	 * recover from any failures any more... -	 */ -	iflag = disable_interrupts(); - -#ifdef CONFIG_NETCONSOLE -	/* Stop the ethernet stack if NetConsole could have left it up */ -	eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) -	/* -	 * turn off USB to prevent the host controller from writing to the -	 * SDRAM while Linux is booting. This could happen (at least for OHCI -	 * controller), because the HCCA (Host Controller Communication Area) -	 * lies within the SDRAM and the host controller writes continously to -	 * this area (as busmaster!). The HccaFrameNumber is for example -	 * updated every 1 ms within the HCCA structure in SDRAM! For more -	 * details see the OpenHCI specification. -	 */ -	usb_stop(); -#endif - -	ret = bootm_load_os(images.os, &load_end, 1); - -	if (ret < 0) { -		if (ret == BOOTM_ERR_RESET) -			do_reset(cmdtp, flag, argc, argv); -		if (ret == BOOTM_ERR_OVERLAP) { -			if (images.legacy_hdr_valid) { -				image_header_t *hdr; -				hdr = &images.legacy_hdr_os_copy; -				if (image_get_type(hdr) == IH_TYPE_MULTI) -					puts("WARNING: legacy format multi " -						"component image " -						"overwritten\n"); -			} else { -				puts("ERROR: new format image overwritten - " -					"must RESET the board to recover\n"); -				bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); -				do_reset(cmdtp, flag, argc, argv); -			} -		} -		if (ret == BOOTM_ERR_UNIMPLEMENTED) { -			if (iflag) -				enable_interrupts(); -			bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); -			return 1; -		} -	} - -	lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load)); - -	if (images.os.type == IH_TYPE_STANDALONE) { -		if (iflag) -			enable_interrupts(); -		/* This may return when 'autostart' is 'no' */ -		bootm_start_standalone(iflag, argc, argv); -		return 0; -	} - -	bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS); - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) -	if (images.os.os == IH_OS_LINUX) -		fixup_silent_linux(); -#endif - -	boot_fn = boot_os[images.os.os]; - -	if (boot_fn == NULL) { -		if (iflag) -			enable_interrupts(); -		printf("ERROR: booting os '%s' (%d) is not supported\n", -			genimg_get_os_name(images.os.os), images.os.os); -		bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); -		return 1; -	} - -	arch_preboot_os(); - -	boot_fn(0, argc, argv, &images); - -	bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); -#ifdef DEBUG -	puts("\n## Control returned to monitor - resetting...\n"); -#endif -	do_reset(cmdtp, flag, argc, argv); - -	return 1; +	return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | +		BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | +		BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP | +		BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1);  }  int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) @@ -816,22 +875,22 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc,  #endif  	/* find out kernel image address */ -	if (argc < 2) { +	if (argc < 1) {  		img_addr = load_addr;  		debug("*  kernel: default image load address = 0x%08lx\n",  				load_addr);  #if defined(CONFIG_FIT) -	} else if (fit_parse_conf(argv[1], load_addr, &img_addr, +	} else if (fit_parse_conf(argv[0], load_addr, &img_addr,  							&fit_uname_config)) {  		debug("*  kernel: config '%s' from image at 0x%08lx\n",  				fit_uname_config, img_addr); -	} else if (fit_parse_subimage(argv[1], load_addr, &img_addr, +	} else if (fit_parse_subimage(argv[0], load_addr, &img_addr,  							&fit_uname_kernel)) {  		debug("*  kernel: subimage '%s' from image at 0x%08lx\n",  				fit_uname_kernel, img_addr);  #endif  	} else { -		img_addr = simple_strtoul(argv[1], NULL, 16); +		img_addr = simple_strtoul(argv[0], NULL, 16);  		debug("*  kernel: cmdline image address = 0x%08lx\n", img_addr);  	} @@ -1346,6 +1405,19 @@ static void fixup_silent_linux(void)  }  #endif /* CONFIG_SILENT_CONSOLE */ +#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9) +static void copy_args(char *dest, int argc, char * const argv[], char delim) +{ +	int i; + +	for (i = 0; i < argc; i++) { +		if (i > 0) +			*dest++ = delim; +		strcpy(dest, argv[i]); +		dest += strlen(argv[i]); +	} +} +#endif  /*******************************************************************/  /* OS booting routines */ @@ -1401,20 +1473,14 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[],  	consdev = "scc3";  #endif -	if (argc > 2) { +	if (argc > 0) {  		ulong len;  		int   i; -		for (i = 2, len = 0; i < argc; i += 1) +		for (i = 0, len = 0; i < argc; i += 1)  			len += strlen(argv[i]) + 1;  		cmdline = malloc(len); - -		for (i = 2, len = 0; i < argc; i += 1) { -			if (i > 2) -				cmdline[len++] = ' '; -			strcpy(&cmdline[len], argv[i]); -			len += strlen(argv[i]); -		} +		copy_args(cmdline, argc, argv, ' ');  	} else if ((cmdline = getenv("bootargs")) == NULL) {  		cmdline = "";  	} @@ -1533,6 +1599,7 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],  			   bootm_headers_t *images)  {  	void (*entry_point)(void); +	char *s;  	if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))  		return 1; @@ -1544,6 +1611,20 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[],  	}  #endif +	/* See README.plan9 */ +	s = getenv("confaddr"); +	if (s != NULL) { +		char *confaddr = (char *)simple_strtoul(s, NULL, 16); + +		if (argc > 0) { +			copy_args(confaddr, argc, argv, '\n'); +		} else { +			s = getenv("bootargs"); +			if (s != NULL) +				strcpy(confaddr, s); +		} +	} +  	entry_point = (void (*)(void))images->ep;  	printf("## Transferring control to Plan 9 (at address %08lx) ...\n", @@ -1663,9 +1744,8 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,  	int ret;  	void *zi_start, *zi_end; -	memset(images, 0, sizeof(bootm_headers_t)); - -	boot_start_lmb(images); +	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, +			      images, 1);  	/* Setup Linux kernel zImage entry point */  	if (argc < 2) { @@ -1684,73 +1764,25 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,  	lmb_reserve(&images->lmb, images->ep, zi_end - zi_start); -	/* Find ramdisk */ -	ret = boot_get_ramdisk(argc, argv, images, IH_INITRD_ARCH, -			&images->rd_start, &images->rd_end); -	if (ret) { -		puts("Ramdisk image is corrupt or invalid\n"); -		return 1; -	} - -#if defined(CONFIG_OF_LIBFDT) -	/* find flattened device tree */ -	ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images, -			   &images->ft_addr, &images->ft_len); -	if (ret) { -		puts("Could not find a valid device tree\n"); -		return 1; -	} - -	set_working_fdt_addr(images->ft_addr); -#endif +	ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER, +			      images, 1); -	return 0; +	return ret;  } -static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	bootm_headers_t	images; +	int ret;  	if (bootz_start(cmdtp, flag, argc, argv, &images))  		return 1; -	/* -	 * We have reached the point of no return: we are going to -	 * overwrite all exception vector code, so we cannot easily -	 * recover from any failures any more... -	 */ -	disable_interrupts(); +	ret = do_bootm_states(cmdtp, flag, argc, argv, +			      BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, +			      &images, 1); -#ifdef CONFIG_NETCONSOLE -	/* Stop the ethernet stack if NetConsole could have left it up */ -	eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) -	/* -	 * turn off USB to prevent the host controller from writing to the -	 * SDRAM while Linux is booting. This could happen (at least for OHCI -	 * controller), because the HCCA (Host Controller Communication Area) -	 * lies within the SDRAM and the host controller writes continously to -	 * this area (as busmaster!). The HccaFrameNumber is for example -	 * updated every 1 ms within the HCCA structure in SDRAM! For more -	 * details see the OpenHCI specification. -	 */ -	usb_stop(); -#endif - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) -	fixup_silent_linux(); -#endif -	arch_preboot_os(); - -	do_bootm_linux(0, argc, argv, &images); -#ifdef DEBUG -	puts("\n## Control returned to monitor - resetting...\n"); -#endif -	do_reset(cmdtp, flag, argc, argv); - -	return 1; +	return ret;  }  #ifdef CONFIG_SYS_LONGHELP diff --git a/common/cmd_ide.c b/common/cmd_ide.c index 78b4aa70b..59e95dfa1 100644 --- a/common/cmd_ide.c +++ b/common/cmd_ide.c @@ -830,7 +830,7 @@ static void ide_ident(block_dev_desc_t *dev_desc)  /* ------------------------------------------------------------------------- */ -ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer)  {  	ulong n = 0;  	unsigned char c; @@ -844,7 +844,7 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)  		lba48 = 1;  	}  #endif -	debug("ide_read dev %d start %lX, blocks " LBAF " buffer at %lX\n", +	debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",  	      device, blknr, blkcnt, (ulong) buffer);  	ide_led(DEVICE_LED(device), 1);	/* LED on       */ @@ -934,8 +934,8 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)  		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=  		    ATA_STAT_DRQ) { -			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", -				device, blknr, c); +			printf("Error (no IRQ) dev %d blk " LBAF ": status " +			       "%#02x\n", device, blknr, c);  			break;  		} @@ -954,7 +954,7 @@ IDE_READ_E:  /* ------------------------------------------------------------------------- */ -ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) +ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer)  {  	ulong n = 0;  	unsigned char c; @@ -1022,8 +1022,8 @@ ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer)  		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=  		    ATA_STAT_DRQ) { -			printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", -				device, blknr, c); +			printf("Error (no IRQ) dev %d blk " LBAF ": status " +				"%#02x\n", device, blknr, c);  			goto WR_OUT;  		} diff --git a/common/cmd_mem.c b/common/cmd_mem.c index 6df00b15d..77eafa0b8 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -551,6 +551,8 @@ static int do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc,  			*cp++;  	}  	unmap_sysmem(buf); + +	return 0;  }  #ifdef CONFIG_LOOPW diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 7d824690b..5f1ed430e 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -147,6 +147,36 @@ U_BOOT_CMD(  	"- display info of the current MMC device"  ); +#ifdef CONFIG_SUPPORT_EMMC_BOOT +static int boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ +	int err; +	err = mmc_boot_part_access(mmc, ack, part_num, access); + +	if ((err == 0) && (access != 0)) { +		printf("\t\t\t!!!Notice!!!\n"); + +		printf("!You must close EMMC boot Partition"); +		printf("after all images are written\n"); + +		printf("!EMMC boot partition has continuity"); +		printf("at image writing time.\n"); + +		printf("!So, do not close the boot partition"); +		printf("before all images are written.\n"); +		return 0; +	} else if ((err == 0) && (access == 0)) +		return 0; +	else if ((err != 0) && (access != 0)) { +		printf("EMMC boot partition-%d OPEN Failed.\n", part_num); +		return 1; +	} else { +		printf("EMMC boot partition-%d CLOSE Failed.\n", part_num); +		return 1; +	} +} +#endif +  static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	enum mmc_state state; @@ -258,8 +288,74 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  				curr_device, mmc->part_num);  		return 0; -	} +#ifdef CONFIG_SUPPORT_EMMC_BOOT +	} else if ((strcmp(argv[1], "open") == 0) || +			(strcmp(argv[1], "close") == 0)) { +		int dev; +		struct mmc *mmc; +		u8 part_num, access = 0; + +		if (argc == 4) { +			dev = simple_strtoul(argv[2], NULL, 10); +			part_num = simple_strtoul(argv[3], NULL, 10); +		} else { +			return CMD_RET_USAGE; +		} + +		mmc = find_mmc_device(dev); +		if (!mmc) { +			printf("no mmc device at slot %x\n", dev); +			return 1; +		} +		if (IS_SD(mmc)) { +			printf("SD device cannot be opened/closed\n"); +			return 1; +		} + +		if ((part_num <= 0) || (part_num > MMC_NUM_BOOT_PARTITION)) { +			printf("Invalid boot partition number:\n"); +			printf("Boot partition number cannot be <= 0\n"); +			printf("EMMC44 supports only 2 boot partitions\n"); +			return 1; +		} + +		if (strcmp(argv[1], "open") == 0) +			access = part_num; /* enable R/W access to boot part*/ +		else +			access = 0; /* No access to boot partition */ + +		/* acknowledge to be sent during boot operation */ +		return boot_part_access(mmc, 1, part_num, access); + +	} else if (strcmp(argv[1], "bootpart") == 0) { +		int dev; +		dev = simple_strtoul(argv[2], NULL, 10); + +		u32 bootsize = simple_strtoul(argv[3], NULL, 10); +		u32 rpmbsize = simple_strtoul(argv[4], NULL, 10); +		struct mmc *mmc = find_mmc_device(dev); +		if (!mmc) { +			printf("no mmc device at slot %x\n", dev); +			return 1; +		} + +		if (IS_SD(mmc)) { +			printf("It is not a EMMC device\n"); +			return 1; +		} + +		if (0 == mmc_boot_partition_size_change(mmc, +							bootsize, rpmbsize)) { +			printf("EMMC boot partition Size %d MB\n", bootsize); +			printf("EMMC RPMB partition Size %d MB\n", rpmbsize); +			return 0; +		} else { +			printf("EMMC boot partition Size change Failed.\n"); +			return 1; +		} +#endif /* CONFIG_SUPPORT_EMMC_BOOT */ +	}  	state = MMC_INVALID;  	if (argc == 5 && strcmp(argv[1], "read") == 0)  		state = MMC_READ; @@ -334,5 +430,14 @@ U_BOOT_CMD(  	"mmc rescan\n"  	"mmc part - lists available partition on current mmc device\n"  	"mmc dev [dev] [part] - show or set current mmc device [partition]\n" -	"mmc list - lists available devices"); +	"mmc list - lists available devices\n" +#ifdef CONFIG_SUPPORT_EMMC_BOOT +	"mmc open <dev> <boot_partition>\n" +	" - Enable boot_part for booting and enable R/W access of boot_part\n" +	"mmc close <dev> <boot_partition>\n" +	" - Enable boot_part for booting and disable access to boot_part\n" +	"mmc bootpart <device num> <boot part size MB> <RPMB part size MB>\n" +	" - change sizes of boot and RPMB partions of specified device\n"  #endif +	); +#endif /* !CONFIG_GENERIC_MMC */ diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 2dbd49cbd..1fb75d8ae 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -26,12 +26,21 @@  #define MAX_TFTP_PATH_LEN 127 +const char *pxe_default_paths[] = { +#ifdef CONFIG_SYS_SOC +	"default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC, +#endif +	"default-" CONFIG_SYS_ARCH, +	"default", +	NULL +}; +  /*   * Like getenv, but prints an error if envvar isn't defined in the   * environment.  It always returns what getenv does, so it can be used in   * place of getenv without changing error handling otherwise.   */ -static char *from_env(char *envvar) +static char *from_env(const char *envvar)  {  	char *ret; @@ -55,37 +64,21 @@ static char *from_env(char *envvar)   */  static int format_mac_pxe(char *outbuf, size_t outbuf_len)  { -	size_t ethaddr_len; -	char *p, *ethaddr; - -	ethaddr = from_env("ethaddr"); +	uchar ethaddr[6]; -	if (!ethaddr) -		return -ENOENT; - -	ethaddr_len = strlen(ethaddr); - -	/* -	 * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at -	 * the end. -	 */ -	if (outbuf_len < ethaddr_len + 4) { -		printf("outbuf is too small (%d < %d)\n", -				outbuf_len, ethaddr_len + 4); +	if (outbuf_len < 21) { +		printf("outbuf is too small (%d < 21)\n", outbuf_len);  		return -EINVAL;  	} -	strcpy(outbuf, "01-"); - -	for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { -		if (*ethaddr == ':') -			*p = '-'; -		else -			*p = tolower(*ethaddr); -	} +	if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(), +					  ethaddr)) +		return -ENOENT; -	*p = '\0'; +	sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x", +		ethaddr[0], ethaddr[1], ethaddr[2], +		ethaddr[3], ethaddr[4], ethaddr[5]);  	return 1;  } @@ -131,14 +124,14 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path,  	return 1;  } -static int (*do_getfile)(char *file_path, char *file_addr); +static int (*do_getfile)(const char *file_path, char *file_addr); -static int do_get_tftp(char *file_path, char *file_addr) +static int do_get_tftp(const char *file_path, char *file_addr)  {  	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};  	tftp_argv[1] = file_addr; -	tftp_argv[2] = file_path; +	tftp_argv[2] = (void *)file_path;  	if (do_tftpb(NULL, 0, 3, tftp_argv))  		return -ENOENT; @@ -148,12 +141,12 @@ static int do_get_tftp(char *file_path, char *file_addr)  static char *fs_argv[5]; -static int do_get_ext2(char *file_path, char *file_addr) +static int do_get_ext2(const char *file_path, char *file_addr)  {  #ifdef CONFIG_CMD_EXT2  	fs_argv[0] = "ext2load";  	fs_argv[3] = file_addr; -	fs_argv[4] = file_path; +	fs_argv[4] = (void *)file_path;  	if (!do_ext2load(NULL, 0, 5, fs_argv))  		return 1; @@ -161,12 +154,12 @@ static int do_get_ext2(char *file_path, char *file_addr)  	return -ENOENT;  } -static int do_get_fat(char *file_path, char *file_addr) +static int do_get_fat(const char *file_path, char *file_addr)  {  #ifdef CONFIG_CMD_FAT  	fs_argv[0] = "fatload";  	fs_argv[3] = file_addr; -	fs_argv[4] = file_path; +	fs_argv[4] = (void *)file_path;  	if (!do_fat_fsload(NULL, 0, 5, fs_argv))  		return 1; @@ -182,7 +175,7 @@ static int do_get_fat(char *file_path, char *file_addr)   *   * Returns 1 for success, or < 0 on error.   */ -static int get_relfile(char *file_path, void *file_addr) +static int get_relfile(const char *file_path, void *file_addr)  {  	size_t path_len;  	char relfile[MAX_TFTP_PATH_LEN+1]; @@ -221,7 +214,7 @@ static int get_relfile(char *file_path, void *file_addr)   *   * Returns 1 on success, or < 0 for error.   */ -static int get_pxe_file(char *file_path, void *file_addr) +static int get_pxe_file(const char *file_path, void *file_addr)  {  	unsigned long config_file_size;  	char *tftp_filesize; @@ -258,7 +251,7 @@ static int get_pxe_file(char *file_path, void *file_addr)   *   * Returns 1 on success or < 0 on error.   */ -static int get_pxelinux_path(char *file, void *pxefile_addr_r) +static int get_pxelinux_path(const char *file, void *pxefile_addr_r)  {  	size_t base_len = strlen(PXELINUX_DIR);  	char path[MAX_TFTP_PATH_LEN+1]; @@ -355,7 +348,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	char *pxefile_addr_str;  	unsigned long pxefile_addr_r; -	int err; +	int err, i = 0;  	do_getfile = do_get_tftp; @@ -376,16 +369,23 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  	 * Keep trying paths until we successfully get a file we're looking  	 * for.  	 */ -	if (pxe_uuid_path((void *)pxefile_addr_r) > 0 -		|| pxe_mac_path((void *)pxefile_addr_r) > 0 -		|| pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 -		|| get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { - +	if (pxe_uuid_path((void *)pxefile_addr_r) > 0 || +	    pxe_mac_path((void *)pxefile_addr_r) > 0 || +	    pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {  		printf("Config file found\n");  		return 0;  	} +	while (pxe_default_paths[i]) { +		if (get_pxelinux_path(pxe_default_paths[i], +				      (void *)pxefile_addr_r) > 0) { +			printf("Config file found\n"); +			return 0; +		} +		i++; +	} +  	printf("Config file not found\n");  	return 1; @@ -398,7 +398,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])   *   * Returns 1 on success or < 0 on error.   */ -static int get_relfile_envaddr(char *file_path, char *envaddr_name) +static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)  {  	unsigned long file_addr;  	char *envaddr; @@ -445,14 +445,17 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name)   * list - lets these form a list, which a pxe_menu struct will hold.   */  struct pxe_label { +	char num[4];  	char *name;  	char *menu;  	char *kernel;  	char *append;  	char *initrd;  	char *fdt; +	int ipappend;  	int attempted;  	int localboot; +	int localboot_val;  	struct list_head list;  }; @@ -533,21 +536,9 @@ static void label_destroy(struct pxe_label *label)  static void label_print(void *data)  {  	struct pxe_label *label = data; -	const char *c = label->menu ? label->menu : label->kernel; - -	printf("%s:\t%s\n", label->name, c); - -	if (label->kernel) -		printf("\t\tkernel: %s\n", label->kernel); - -	if (label->append) -		printf("\t\tappend: %s\n", label->append); +	const char *c = label->menu ? label->menu : label->name; -	if (label->initrd) -		printf("\t\tinitrd: %s\n", label->initrd); - -	if (label->fdt) -		printf("\tfdt: %s\n", label->fdt); +	printf("%s:\t%s\n", label->num, c);  }  /* @@ -591,34 +582,43 @@ static int label_localboot(struct pxe_label *label)   * If the label specifies an 'append' line, its contents will overwrite that   * of the 'bootargs' environment variable.   */ -static void label_boot(struct pxe_label *label) +static int label_boot(struct pxe_label *label)  {  	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; +	char initrd_str[22]; +	char mac_str[29] = ""; +	char ip_str[68] = ""; +	char *bootargs;  	int bootm_argc = 3; +	int len = 0;  	label_print(label);  	label->attempted = 1;  	if (label->localboot) { -		label_localboot(label); -		return; +		if (label->localboot_val >= 0) +			label_localboot(label); +		return 0;  	}  	if (label->kernel == NULL) {  		printf("No kernel given, skipping %s\n",  				label->name); -		return; +		return 1;  	}  	if (label->initrd) {  		if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {  			printf("Skipping %s for failure retrieving initrd\n",  					label->name); -			return; +			return 1;  		} -		bootm_argv[2] = getenv("ramdisk_addr_r"); +		bootm_argv[2] = initrd_str; +		strcpy(bootm_argv[2], getenv("ramdisk_addr_r")); +		strcat(bootm_argv[2], ":"); +		strcat(bootm_argv[2], getenv("filesize"));  	} else {  		bootm_argv[2] = "-";  	} @@ -626,11 +626,43 @@ static void label_boot(struct pxe_label *label)  	if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {  		printf("Skipping %s for failure retrieving kernel\n",  				label->name); -		return; +		return 1; +	} + +	if (label->ipappend & 0x1) { +		sprintf(ip_str, " ip=%s:%s:%s:%s", +			getenv("ipaddr"), getenv("serverip"), +			getenv("gatewayip"), getenv("netmask")); +		len += strlen(ip_str); +	} + +	if (label->ipappend & 0x2) { +		int err; +		strcpy(mac_str, " BOOTIF="); +		err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); +		if (err < 0) +			mac_str[0] = '\0'; +		len += strlen(mac_str);  	}  	if (label->append) -		setenv("bootargs", label->append); +		len += strlen(label->append); + +	if (len) { +		bootargs = malloc(len + 1); +		if (!bootargs) +			return 1; +		bootargs[0] = '\0'; +		if (label->append) +			strcpy(bootargs, label->append); +		strcat(bootargs, ip_str); +		strcat(bootargs, mac_str); + +		setenv("bootargs", bootargs); +		printf("append: %s\n", bootargs); + +		free(bootargs); +	}  	bootm_argv[1] = getenv("kernel_addr_r"); @@ -654,7 +686,7 @@ static void label_boot(struct pxe_label *label)  		if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {  			printf("Skipping %s for failure retrieving fdt\n",  					label->name); -			return; +			return 1;  		}  	} else  		bootm_argv[3] = getenv("fdt_addr"); @@ -663,6 +695,12 @@ static void label_boot(struct pxe_label *label)  		bootm_argc = 4;  	do_bootm(NULL, 0, bootm_argc, bootm_argv); + +#ifdef CONFIG_CMD_BOOTZ +	/* Try booting a zImage if do_bootm returns */ +	do_bootz(NULL, 0, bootm_argc, bootm_argv); +#endif +	return 1;  }  /* @@ -685,6 +723,8 @@ enum token_type {  	T_PROMPT,  	T_INCLUDE,  	T_FDT, +	T_ONTIMEOUT, +	T_IPAPPEND,  	T_INVALID  }; @@ -713,6 +753,8 @@ static const struct token keywords[] = {  	{"initrd", T_INITRD},  	{"include", T_INCLUDE},  	{"fdt", T_FDT}, +	{"ontimeout", T_ONTIMEOUT,}, +	{"ipappend", T_IPAPPEND,},  	{NULL, T_INVALID}  }; @@ -903,7 +945,6 @@ static int parse_integer(char **c, int *dst)  {  	struct token t;  	char *s = *c; -	unsigned long temp;  	get_token(c, &t, L_SLITERAL); @@ -912,12 +953,7 @@ static int parse_integer(char **c, int *dst)  		return -EINVAL;  	} -	if (strict_strtoul(t.val, 10, &temp) < 0) { -		printf("Expected unsigned integer: %s\n", t.val); -		return -EINVAL; -	} - -	*dst = (int)temp; +	*dst = simple_strtol(t.val, NULL, 10);  	free(t.val); @@ -1016,10 +1052,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg,  	switch (t.type) {  	case T_DEFAULT: -		if (cfg->default_label) -			free(cfg->default_label); - -		cfg->default_label = strdup(label->name); +		if (!cfg->default_label) +			cfg->default_label = strdup(label->name);  		if (!cfg->default_label)  			return -ENOMEM; @@ -1108,7 +1142,12 @@ static int parse_label(char **c, struct pxe_menu *cfg)  			break;  		case T_LOCALBOOT: -			err = parse_integer(c, &label->localboot); +			label->localboot = 1; +			err = parse_integer(c, &label->localboot_val); +			break; + +		case T_IPAPPEND: +			err = parse_integer(c, &label->ipappend);  			break;  		case T_EOL: @@ -1164,6 +1203,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  		err = 0;  		switch (t.type) {  		case T_MENU: +			cfg->prompt = 1;  			err = parse_menu(&p, cfg, b, nest_level);  			break; @@ -1176,6 +1216,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  			break;  		case T_DEFAULT: +		case T_ONTIMEOUT:  			err = parse_sliteral(&p, &label_name);  			if (label_name) { @@ -1193,7 +1234,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)  			break;  		case T_PROMPT: -			err = parse_integer(&p, &cfg->prompt); +			eol_or_eof(&p);  			break;  		case T_EOL: @@ -1276,6 +1317,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)  	struct list_head *pos;  	struct menu *m;  	int err; +	int i = 1; +	char *default_num = NULL;  	/*  	 * Create a menu and add items for all the labels. @@ -1289,18 +1332,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)  	list_for_each(pos, &cfg->labels) {  		label = list_entry(pos, struct pxe_label, list); -		if (menu_item_add(m, label->name, label) != 1) { +		sprintf(label->num, "%d", i++); +		if (menu_item_add(m, label->num, label) != 1) {  			menu_destroy(m);  			return NULL;  		} +		if (cfg->default_label && +		    (strcmp(label->name, cfg->default_label) == 0)) +			default_num = label->num; +  	}  	/*  	 * After we've created items for each label in the menu, set the  	 * menu's default label if one was specified.  	 */ -	if (cfg->default_label) { -		err = menu_default_set(m, cfg->default_label); +	if (default_num) { +		err = menu_default_set(m, default_num);  		if (err != 1) {  			if (err != -ENOENT) {  				menu_destroy(m); @@ -1367,10 +1415,13 @@ static void handle_pxe_menu(struct pxe_menu *cfg)  	 * we give up.  	 */ -	if (err == 1) -		label_boot(choice); -	else if (err != -ENOENT) +	if (err == 1) { +		err = label_boot(choice); +		if (!err) +			return; +	} else if (err != -ENOENT) {  		return; +	}  	boot_unattempted_labels(cfg);  } diff --git a/common/cmd_trace.c b/common/cmd_trace.c new file mode 100644 index 000000000..ec3137a8a --- /dev/null +++ b/common/cmd_trace.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * 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 <trace.h> +#include <asm/io.h> + +static int get_args(int argc, char * const argv[], char **buff, +		    size_t *buff_ptr, size_t *buff_size) +{ +	if (argc < 2) +		return -1; +	if (argc < 4) { +		*buff_size = getenv_ulong("profsize", 16, 0); +		*buff = map_sysmem(getenv_ulong("profbase", 16, 0), +				   *buff_size); +		*buff_ptr = getenv_ulong("profoffset", 16, 0); +	} else { +		*buff_size = simple_strtoul(argv[3], NULL, 16); +		*buff = map_sysmem(simple_strtoul(argv[2], NULL, 16), +				   *buff_size); +		*buff_ptr = 0; +	}; +	return 0; +} + +static int create_func_list(int argc, char * const argv[]) +{ +	size_t buff_size, avail, buff_ptr, used; +	unsigned int needed; +	char *buff; +	int err; + +	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) +		return -1; + +	avail = buff_size - buff_ptr; +	err = trace_list_functions(buff + buff_ptr, avail, &needed); +	if (err) +		printf("Error: truncated (%#x bytes needed)\n", needed); +	used = min(avail, needed); +	printf("Function trace dumped to %08lx, size %#zx\n", +	       (ulong)map_to_sysmem(buff + buff_ptr), used); +	setenv_hex("profbase", map_to_sysmem(buff)); +	setenv_hex("profsize", buff_size); +	setenv_hex("profoffset", buff_ptr + used); + +	return 0; +} + +static int create_call_list(int argc, char * const argv[]) +{ +	size_t buff_size, avail, buff_ptr, used; +	unsigned int needed; +	char *buff; +	int err; + +	if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) +		return -1; + +	avail = buff_size - buff_ptr; +	err = trace_list_calls(buff + buff_ptr, avail, &needed); +	if (err) +		printf("Error: truncated (%#x bytes needed)\n", needed); +	used = min(avail, needed); +	printf("Call list dumped to %08lx, size %#zx\n", +	       (ulong)map_to_sysmem(buff + buff_ptr), used); + +	setenv_hex("profbase", map_to_sysmem(buff)); +	setenv_hex("profsize", buff_size); +	setenv_hex("profoffset", buff_ptr + used); + +	return 0; +} + +int do_trace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	const char *cmd = argc < 2 ? NULL : argv[1]; + +	if (!cmd) +		return cmd_usage(cmdtp); +	switch (*cmd) { +	case 'p': +		trace_set_enabled(0); +		break; +	case 'c': +		if (create_call_list(argc, argv)) +			return cmd_usage(cmdtp); +		break; +	case 'r': +		trace_set_enabled(1); +		break; +	case 'f': +		if (create_func_list(argc, argv)) +			return cmd_usage(cmdtp); +		break; +	case 's': +		trace_print_stats(); +		break; +	default: +		return CMD_RET_USAGE; +	} + +	return 0; +} + +U_BOOT_CMD( +	trace,	4,	1,	do_trace, +	"trace utility commands", +	"stats                        - display tracing statistics\n" +	"trace pause                        - pause tracing\n" +	"trace resume                       - resume tracing\n" +	"trace funclist [<addr> <size>]     - dump function list into buffer\n" +	"trace calls  [<addr> <size>]       " +		"- dump function call trace into buffer" +); diff --git a/common/image-fdt.c b/common/image-fdt.c index 0d421d92f..d99f444de 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -248,13 +248,16 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,  	ulong		default_addr;  	int		fdt_noffset;  #endif +	const char *select = NULL;  	*of_flat_tree = NULL;  	*of_size = 0; -	if (argc > 3 || genimg_has_config(images)) { +	if (argc > 2) +		select = argv[2]; +	if (select || genimg_has_config(images)) {  #if defined(CONFIG_FIT) -		if (argc > 3) { +		if (select) {  			/*  			 * If the FDT blob comes from the FIT image and the  			 * FIT image address is omitted in the command line @@ -268,18 +271,18 @@ int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,  			else  				default_addr = load_addr; -			if (fit_parse_conf(argv[3], default_addr, +			if (fit_parse_conf(select, default_addr,  					   &fdt_addr, &fit_uname_config)) {  				debug("*  fdt: config '%s' from image at 0x%08lx\n",  				      fit_uname_config, fdt_addr); -			} else if (fit_parse_subimage(argv[3], default_addr, +			} else if (fit_parse_subimage(select, default_addr,  				   &fdt_addr, &fit_uname_fdt)) {  				debug("*  fdt: subimage '%s' from image at 0x%08lx\n",  				      fit_uname_fdt, fdt_addr);  			} else  #endif  			{ -				fdt_addr = simple_strtoul(argv[3], NULL, 16); +				fdt_addr = simple_strtoul(select, NULL, 16);  				debug("*  fdt: cmdline image address = 0x%08lx\n",  				      fdt_addr);  			} diff --git a/common/image-fit.c b/common/image-fit.c index f40f1603f..b75e119d9 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -234,42 +234,45 @@ void fit_print_contents(const void *fit)   * @fit: pointer to the FIT format image header   * @noffset: offset of the hash node   * @p: pointer to prefix string + * @type: Type of information to print ("hash" or "sign")   *   * fit_image_print_data() lists properies for the processed hash node   * + * This function avoid using puts() since it prints a newline on the host + * but does not in U-Boot. + *   * returns:   *     no returned results   */ -static void fit_image_print_data(const void *fit, int noffset, const char *p) +static void fit_image_print_data(const void *fit, int noffset, const char *p, +				 const char *type)  { -	char *algo; +	const char *keyname;  	uint8_t *value;  	int value_len; -	int i, ret; - -	/* -	 * Check subnode name, must be equal to "hash". -	 * Multiple hash nodes require unique unit node -	 * names, e.g. hash@1, hash@2, etc. -	 */ -	if (strncmp(fit_get_name(fit, noffset, NULL), -		    FIT_HASH_NODENAME, -		    strlen(FIT_HASH_NODENAME)) != 0) -		return; +	char *algo; +	int required; +	int ret, i; -	debug("%s  Hash node:    '%s'\n", p, +	debug("%s  %s node:    '%s'\n", p, type,  	      fit_get_name(fit, noffset, NULL)); - -	printf("%s  Hash algo:    ", p); +	printf("%s  %s algo:    ", p, type);  	if (fit_image_hash_get_algo(fit, noffset, &algo)) {  		printf("invalid/unsupported\n");  		return;  	} -	printf("%s\n", algo); +	printf("%s", algo); +	keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); +	required = fdt_getprop(fit, noffset, "required", NULL) != NULL; +	if (keyname) +		printf(":%s", keyname); +	if (required) +		printf(" (required)"); +	printf("\n");  	ret = fit_image_hash_get_value(fit, noffset, &value,  					&value_len); -	printf("%s  Hash value:   ", p); +	printf("%s  %s value:   ", p, type);  	if (ret) {  		printf("unavailable\n");  	} else { @@ -278,7 +281,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p)  		printf("\n");  	} -	debug("%s  Hash len:     %d\n", p, value_len); +	debug("%s  %s len:     %d\n", p, type, value_len); + +	/* Signatures have a time stamp */ +	if (IMAGE_ENABLE_TIMESTAMP && keyname) { +		time_t timestamp; + +		printf("%s  Timestamp:    ", p); +		if (fit_get_timestamp(fit, noffset, ×tamp)) +			printf("unavailable\n"); +		else +			genimg_print_time(timestamp); +	}  }  /** @@ -303,8 +317,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset,  	 * names, e.g. hash@1, hash@2, signature@1, signature@2, etc.  	 */  	name = fit_get_name(fit, noffset, NULL); -	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) -		fit_image_print_data(fit, noffset, p); +	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { +		fit_image_print_data(fit, noffset, p, "Hash"); +	} else if (!strncmp(name, FIT_SIG_NODENAME, +				strlen(FIT_SIG_NODENAME))) { +		fit_image_print_data(fit, noffset, p, "Sign"); +	}  }  /** @@ -944,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset)  {  	const void	*data;  	size_t		size; -	int		noffset; +	int		noffset = 0;  	char		*err_msg = ""; +	int verify_all = 1; +	int ret;  	/* Get image data and data length */  	if (fit_image_get_data(fit, image_noffset, &data, &size)) {  		err_msg = "Can't get image data/size"; -		return 0; +		goto error; +	} + +	/* Verify all required signatures */ +	if (IMAGE_ENABLE_VERIFY && +	    fit_image_verify_required_sigs(fit, image_noffset, data, size, +					   gd_fdt_blob(), &verify_all)) { +		err_msg = "Unable to verify required signature"; +		goto error;  	}  	/* Process all hash subnodes of the component image node */ @@ -970,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset)  						 &err_msg))  				goto error;  			puts("+ "); +		} else if (IMAGE_ENABLE_VERIFY && verify_all && +				!strncmp(name, FIT_SIG_NODENAME, +					strlen(FIT_SIG_NODENAME))) { +			ret = fit_image_check_sig(fit, noffset, data, +							size, -1, &err_msg); +			if (ret) +				puts("- "); +			else +				puts("+ ");  		}  	} diff --git a/common/image-sig.c b/common/image-sig.c new file mode 100644 index 000000000..5d907cfc4 --- /dev/null +++ b/common/image-sig.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * 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 +#include "mkimage.h" +#include <time.h> +#else +#include <common.h> +#include <malloc.h> +DECLARE_GLOBAL_DATA_PTR; +#endif /* !USE_HOSTCC*/ +#include <image.h> +#include <rsa.h> + +#define IMAGE_MAX_HASHED_NODES		100 + +struct image_sig_algo image_sig_algos[] = { +	{ +		"sha1,rsa2048", +		rsa_sign, +		rsa_add_verify_data, +		rsa_verify, +	} +}; + +struct image_sig_algo *image_get_sig_algo(const char *name) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) { +		if (!strcmp(image_sig_algos[i].name, name)) +			return &image_sig_algos[i]; +	} + +	return NULL; +} + +/** + * fit_region_make_list() - Make a list of image regions + * + * Given a list of fdt_regions, create a list of image_regions. This is a + * simple conversion routine since the FDT and image code use different + * structures. + * + * @fit: FIT image + * @fdt_regions: Pointer to FDT regions + * @count: Number of FDT regions + * @region: Pointer to image regions, which must hold @count records. If + * region is NULL, then (except for an SPL build) the array will be + * allocated. + * @return: Pointer to image regions + */ +struct image_region *fit_region_make_list(const void *fit, +		struct fdt_region *fdt_regions, int count, +		struct image_region *region) +{ +	int i; + +	debug("Hash regions:\n"); +	debug("%10s %10s\n", "Offset", "Size"); + +	/* +	 * Use malloc() except in SPL (to save code size). In SPL the caller +	 * must allocate the array. +	 */ +#ifndef CONFIG_SPL_BUILD +	if (!region) +		region = calloc(sizeof(*region), count); +#endif +	if (!region) +		return NULL; +	for (i = 0; i < count; i++) { +		debug("%10x %10x\n", fdt_regions[i].offset, +		      fdt_regions[i].size); +		region[i].data = fit + fdt_regions[i].offset; +		region[i].size = fdt_regions[i].size; +	} + +	return region; +} + +static int fit_image_setup_verify(struct image_sign_info *info, +		const void *fit, int noffset, int required_keynode, +		char **err_msgp) +{ +	char *algo_name; + +	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { +		*err_msgp = "Can't get hash algo property"; +		return -1; +	} +	memset(info, '\0', sizeof(*info)); +	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); +	info->fit = (void *)fit; +	info->node_offset = noffset; +	info->algo = image_get_sig_algo(algo_name); +	info->fdt_blob = gd_fdt_blob(); +	info->required_keynode = required_keynode; +	printf("%s:%s", algo_name, info->keyname); + +	if (!info->algo) { +		*err_msgp = "Unknown signature algorithm"; +		return -1; +	} + +	return 0; +} + +int fit_image_check_sig(const void *fit, int noffset, const void *data, +		size_t size, int required_keynode, char **err_msgp) +{ +	struct image_sign_info info; +	struct image_region region; +	uint8_t *fit_value; +	int fit_value_len; + +	*err_msgp = NULL; +	if (fit_image_setup_verify(&info, fit, noffset, required_keynode, +				   err_msgp)) +		return -1; + +	if (fit_image_hash_get_value(fit, noffset, &fit_value, +				     &fit_value_len)) { +		*err_msgp = "Can't get hash value property"; +		return -1; +	} + +	region.data = data; +	region.size = size; + +	if (info.algo->verify(&info, ®ion, 1, fit_value, fit_value_len)) { +		*err_msgp = "Verification failed"; +		return -1; +	} + +	return 0; +} + +static int fit_image_verify_sig(const void *fit, int image_noffset, +		const char *data, size_t size, const void *sig_blob, +		int sig_offset) +{ +	int noffset; +	char *err_msg = ""; +	int verified = 0; +	int ret; + +	/* Process all hash subnodes of the component image node */ +	for (noffset = fdt_first_subnode(fit, image_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		const char *name = fit_get_name(fit, noffset, NULL); + +		if (!strncmp(name, FIT_SIG_NODENAME, +			     strlen(FIT_SIG_NODENAME))) { +			ret = fit_image_check_sig(fit, noffset, data, +							size, -1, &err_msg); +			if (ret) { +				puts("- "); +			} else { +				puts("+ "); +				verified = 1; +				break; +			} +		} +	} + +	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { +		err_msg = "Corrupted or truncated tree"; +		goto error; +	} + +	return verified ? 0 : -EPERM; + +error: +	printf(" error!\n%s for '%s' hash node in '%s' image node\n", +	       err_msg, fit_get_name(fit, noffset, NULL), +	       fit_get_name(fit, image_noffset, NULL)); +	return -1; +} + +int fit_image_verify_required_sigs(const void *fit, int image_noffset, +		const char *data, size_t size, const void *sig_blob, +		int *no_sigsp) +{ +	int verify_count = 0; +	int noffset; +	int sig_node; + +	/* Work out what we need to verify */ +	*no_sigsp = 1; +	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); +	if (sig_node < 0) { +		debug("%s: No signature node found: %s\n", __func__, +		      fdt_strerror(sig_node)); +		return 0; +	} + +	for (noffset = fdt_first_subnode(sig_blob, sig_node); +	     noffset >= 0; +	     noffset = fdt_next_subnode(sig_blob, noffset)) { +		const char *required; +		int ret; + +		required = fdt_getprop(sig_blob, noffset, "required", NULL); +		if (!required || strcmp(required, "image")) +			continue; +		ret = fit_image_verify_sig(fit, image_noffset, data, size, +					sig_blob, noffset); +		if (ret) { +			printf("Failed to verify required signature '%s'\n", +			       fit_get_name(sig_blob, noffset, NULL)); +			return ret; +		} +		verify_count++; +	} + +	if (verify_count) +		*no_sigsp = 0; + +	return 0; +} + +int fit_config_check_sig(const void *fit, int noffset, int required_keynode, +			 char **err_msgp) +{ +	char * const exc_prop[] = {"data"}; +	const char *prop, *end, *name; +	struct image_sign_info info; +	const uint32_t *strings; +	uint8_t *fit_value; +	int fit_value_len; +	int max_regions; +	int i, prop_len; +	char path[200]; +	int count; + +	debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(), +	      fit_get_name(fit, noffset, NULL), +	      fit_get_name(gd_fdt_blob(), required_keynode, NULL)); +	*err_msgp = NULL; +	if (fit_image_setup_verify(&info, fit, noffset, required_keynode, +				   err_msgp)) +		return -1; + +	if (fit_image_hash_get_value(fit, noffset, &fit_value, +				     &fit_value_len)) { +		*err_msgp = "Can't get hash value property"; +		return -1; +	} + +	/* Count the number of strings in the property */ +	prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len); +	end = prop ? prop + prop_len : prop; +	for (name = prop, count = 0; name < end; name++) +		if (!*name) +			count++; +	if (!count) { +		*err_msgp = "Can't get hashed-nodes property"; +		return -1; +	} + +	/* Add a sanity check here since we are using the stack */ +	if (count > IMAGE_MAX_HASHED_NODES) { +		*err_msgp = "Number of hashed nodes exceeds maximum"; +		return -1; +	} + +	/* Create a list of node names from those strings */ +	char *node_inc[count]; + +	debug("Hash nodes (%d):\n", count); +	for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { +		debug("   '%s'\n", name); +		node_inc[i] = (char *)name; +	} + +	/* +	 * Each node can generate one region for each sub-node. Allow for +	 * 7 sub-nodes (hash@1, signature@1, etc.) and some extra. +	 */ +	max_regions = 20 + count * 7; +	struct fdt_region fdt_regions[max_regions]; + +	/* Get a list of regions to hash */ +	count = fdt_find_regions(fit, node_inc, count, +			exc_prop, ARRAY_SIZE(exc_prop), +			fdt_regions, max_regions - 1, +			path, sizeof(path), 0); +	if (count < 0) { +		*err_msgp = "Failed to hash configuration"; +		return -1; +	} +	if (count == 0) { +		*err_msgp = "No data to hash"; +		return -1; +	} +	if (count >= max_regions - 1) { +		*err_msgp = "Too many hash regions"; +		return -1; +	} + +	/* Add the strings */ +	strings = fdt_getprop(fit, noffset, "hashed-strings", NULL); +	if (strings) { +		fdt_regions[count].offset = fdt_off_dt_strings(fit) + +				fdt32_to_cpu(strings[0]); +		fdt_regions[count].size = fdt32_to_cpu(strings[1]); +		count++; +	} + +	/* Allocate the region list on the stack */ +	struct image_region region[count]; + +	fit_region_make_list(fit, fdt_regions, count, region); +	if (info.algo->verify(&info, region, count, fit_value, +			      fit_value_len)) { +		*err_msgp = "Verification failed"; +		return -1; +	} + +	return 0; +} + +static int fit_config_verify_sig(const void *fit, int conf_noffset, +		const void *sig_blob, int sig_offset) +{ +	int noffset; +	char *err_msg = ""; +	int verified = 0; +	int ret; + +	/* Process all hash subnodes of the component conf node */ +	for (noffset = fdt_first_subnode(fit, conf_noffset); +	     noffset >= 0; +	     noffset = fdt_next_subnode(fit, noffset)) { +		const char *name = fit_get_name(fit, noffset, NULL); + +		if (!strncmp(name, FIT_SIG_NODENAME, +			     strlen(FIT_SIG_NODENAME))) { +			ret = fit_config_check_sig(fit, noffset, sig_offset, +						   &err_msg); +			if (ret) { +				puts("- "); +			} else { +				puts("+ "); +				verified = 1; +				break; +			} +		} +	} + +	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { +		err_msg = "Corrupted or truncated tree"; +		goto error; +	} + +	return verified ? 0 : -EPERM; + +error: +	printf(" error!\n%s for '%s' hash node in '%s' config node\n", +	       err_msg, fit_get_name(fit, noffset, NULL), +	       fit_get_name(fit, conf_noffset, NULL)); +	return -1; +} + +int fit_config_verify_required_sigs(const void *fit, int conf_noffset, +		const void *sig_blob) +{ +	int noffset; +	int sig_node; + +	/* Work out what we need to verify */ +	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); +	if (sig_node < 0) { +		debug("%s: No signature node found: %s\n", __func__, +		      fdt_strerror(sig_node)); +		return 0; +	} + +	for (noffset = fdt_first_subnode(sig_blob, sig_node); +	     noffset >= 0; +	     noffset = fdt_next_subnode(sig_blob, noffset)) { +		const char *required; +		int ret; + +		required = fdt_getprop(sig_blob, noffset, "required", NULL); +		if (!required || strcmp(required, "conf")) +			continue; +		ret = fit_config_verify_sig(fit, conf_noffset, sig_blob, +					    noffset); +		if (ret) { +			printf("Failed to verify required signature '%s'\n", +			       fit_get_name(sig_blob, noffset, NULL)); +			return ret; +		} +	} + +	return 0; +} + +int fit_config_verify(const void *fit, int conf_noffset) +{ +	return !fit_config_verify_required_sigs(fit, conf_noffset, +						gd_fdt_blob()); +} diff --git a/common/image.c b/common/image.c index f863502ab..1be384f26 100644 --- a/common/image.c +++ b/common/image.c @@ -816,20 +816,23 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  	ulong		default_addr;  	int		rd_noffset;  #endif +	const char *select = NULL;  	*rd_start = 0;  	*rd_end = 0; +	if (argc >= 2) +		select = argv[1];  	/*  	 * Look for a '-' which indicates to ignore the  	 * ramdisk argument  	 */ -	if ((argc >= 3) && (strcmp(argv[2], "-") ==  0)) { +	if (select && strcmp(select, "-") ==  0) {  		debug("## Skipping init Ramdisk\n");  		rd_len = rd_data = 0; -	} else if (argc >= 3 || genimg_has_config(images)) { +	} else if (select || genimg_has_config(images)) {  #if defined(CONFIG_FIT) -		if (argc >= 3) { +		if (select) {  			/*  			 * If the init ramdisk comes from the FIT image and  			 * the FIT image address is omitted in the command @@ -841,12 +844,12 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  			else  				default_addr = load_addr; -			if (fit_parse_conf(argv[2], default_addr, -						&rd_addr, &fit_uname_config)) { +			if (fit_parse_conf(select, default_addr, +					   &rd_addr, &fit_uname_config)) {  				debug("*  ramdisk: config '%s' from image at "  						"0x%08lx\n",  						fit_uname_config, rd_addr); -			} else if (fit_parse_subimage(argv[2], default_addr, +			} else if (fit_parse_subimage(select, default_addr,  						&rd_addr, &fit_uname_ramdisk)) {  				debug("*  ramdisk: subimage '%s' from image at "  						"0x%08lx\n", @@ -854,7 +857,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  			} else  #endif  			{ -				rd_addr = simple_strtoul(argv[2], NULL, 16); +				rd_addr = simple_strtoul(select, NULL, 16);  				debug("*  ramdisk: cmdline image address = "  						"0x%08lx\n",  						rd_addr); @@ -918,7 +921,10 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,  #endif  		default:  #ifdef CONFIG_SUPPORT_RAW_INITRD -			if (argc >= 3 && (end = strchr(argv[2], ':'))) { +			end = NULL; +			if (select) +				end = strchr(select, ':'); +			if (end) {  				rd_len = simple_strtoul(++end, NULL, 16);  				rd_data = rd_addr;  			} else diff --git a/common/usb_storage.c b/common/usb_storage.c index 457970f77..4599d03c3 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -170,9 +170,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *us,  		      block_dev_desc_t *dev_desc);  int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,  		      struct us_data *ss); -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr,  			    lbaint_t blkcnt, void *buffer); -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr,  			     lbaint_t blkcnt, const void *buffer);  struct usb_device * usb_get_dev_index(int index);  void uhci_show_temp_int_td(void); @@ -1054,7 +1054,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,  }  #endif /* CONFIG_USB_BIN_FIXUP */ -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr,  			    lbaint_t blkcnt, void *buffer)  {  	lbaint_t start, blks; @@ -1127,7 +1127,7 @@ retry_it:  	return blkcnt;  } -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr,  				lbaint_t blkcnt, const void *buffer)  {  	lbaint_t start, blks;  |