summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile2
-rw-r--r--common/board_f.c17
-rw-r--r--common/board_r.c11
-rw-r--r--common/bootstage.c26
-rw-r--r--common/cmd_bootm.c546
-rw-r--r--common/cmd_ide.c14
-rw-r--r--common/cmd_mem.c2
-rw-r--r--common/cmd_trace.c133
-rw-r--r--common/image-fdt.c13
-rw-r--r--common/image-fit.c83
-rw-r--r--common/image-sig.c422
-rw-r--r--common/image.c22
-rw-r--r--common/usb_storage.c8
13 files changed, 968 insertions, 331 deletions
diff --git a/common/Makefile b/common/Makefile
index 35816037e..48791b7ff 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -169,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
@@ -242,6 +243,7 @@ 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 e452fcac9..ba0bcd4e3 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,9 +339,6 @@ 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;
}
@@ -446,7 +470,7 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
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 +481,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,108 +499,225 @@ 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 boot_selected_os(int argc, char * const argv[], int state,
+ bootm_headers_t *images, boot_os_fn *boot_fn, ulong *iflag)
+{
+ if (images->os.type == IH_TYPE_STANDALONE) {
+ /* This may return when 'autostart' is 'no' */
+ bootm_start_standalone(argc, argv);
+ return 0;
+ }
+ /*
+ * 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
+#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.
+ *
+ * @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)
+{
+ boot_os_fn *boot_fn;
+ ulong iflag = 0;
+ int ret = 0;
+
+ images->state |= states;
+
+ /*
+ * 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);
+
+ if (!ret && (states & BOOTM_STATE_FINDOS))
+ ret = bootm_find_os(cmdtp, flag, argc, argv);
+
+ if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
+ ret = bootm_find_other(cmdtp, flag, argc, argv);
+ argc = 0; /* consume the args */
+ }
+
+ /* Load the OS */
+ if (!ret && (states & BOOTM_STATE_LOADOS)) {
+ ulong load_end;
+
+ ret = bootm_load_os(images->os, &load_end, 0);
+ if (!ret) {
+ lmb_reserve(&images->lmb, images->os.load,
+ (load_end - images->os.load));
+ }
+ }
+
+ /* Relocate the ramdisk */
+#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
+ if (!ret && (states & BOOTM_STATE_RAMDISK)) {
+ ulong rd_len = images->rd_end - images->rd_start;
+
+ 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);
+ }
+ }
+#endif
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
+ 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
+
+ /* 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, &iflag);
+ if (!ret && cmd_list)
+ ret = run_command_list(cmd_list, -1, flag);
+ }
+#endif
+ /* 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, &iflag);
+
+ /* Deal with any fallout */
+ if (ret < 0) {
+ if (ret == BOOTM_ERR_UNIMPLEMENTED) {
+ if (iflag)
+ enable_interrupts();
+ bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ return 1;
+ } else if (ret == BOOTM_ERR_OVERLAP) {
+ 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");
+ } else {
+ puts("ERROR: new format image overwritten - must RESET the board to recover\n");
+ bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
+ ret = BOOTM_ERR_RESET;
+ }
+ }
+ if (ret == BOOTM_ERR_RESET)
+ do_reset(cmdtp, flag, argc, argv);
+ }
+ if (iflag)
+ enable_interrupts();
+ if (ret)
+ 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;
- boot_os_fn *boot_fn;
- c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
+ c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub));
+ argc--; argv++;
if (c) {
state = (long)c->cmd;
-
- /* treat start special since it resets the state machine */
- if (state == BOOTM_STATE_START) {
- argc--;
- argv++;
- return bootm_start(cmdtp, flag, argc, argv);
- }
+ if (state == BOOTM_STATE_START)
+ state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER;
} else {
/* Unrecognized command */
return CMD_RET_USAGE;
}
- if (images.state < BOOTM_STATE_START ||
- images.state >= state) {
+ if (state != BOOTM_STATE_START && images.state >= state) {
printf("Trying to execute a command out of order\n");
return CMD_RET_USAGE;
}
- images.state |= state;
- boot_fn = boot_os[images.os.os];
-
- switch (state) {
- 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 = boot_ramdisk_high(&images.lmb, images.rd_start,
- rd_len, &images.initrd_start, &images.initrd_end);
- if (ret)
- return 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;
- }
-#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();
-#endif
- arch_preboot_os();
- boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images);
- break;
- }
+ ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0);
return ret;
}
@@ -587,10 +728,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 +748,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 +765,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 +863,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 +1393,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 +1461,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 +1587,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 +1599,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 +1732,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 +1752,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;
- }
+ ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_FINDOTHER,
+ images, 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
-
- return 0;
+ return ret;
}
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();
-
-#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);
+ ret = do_bootm_states(cmdtp, flag, argc, argv,
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO,
+ &images, 1);
- 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_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, &timestamp))
+ 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, &region, 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;