summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2011-12-06 08:53:26 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2011-12-15 11:07:11 +0100
commitd4e5c6b8a03d31c00084d38e40d9811267f00289 (patch)
tree501db64efe6c21d7e8a254eb4e478838ff8c9446 /commands
parent390249968c4eeaceddd26a1cdeca5728f5b87b18 (diff)
downloadbarebox-d4e5c6b8a03d31c00084d38e40d9811267f00289.tar.gz
barebox-d4e5c6b8a03d31c00084d38e40d9811267f00289.tar.xz
bootm: use new uimage code
This switches the bootm code to the new uimage code. Also bootm can now handle other types of images than uImages. Currently the only architecture making use of this is arm which allows to boot zImages, raw images and barebox images. I intended to make a more bisectable series from this but I failed becuase there are many dependencies and no matter how I tried the patches grew bigger and and bigger. So I decided to put this all in a single patch. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'commands')
-rw-r--r--commands/Kconfig22
-rw-r--r--commands/bootm.c451
2 files changed, 348 insertions, 125 deletions
diff --git a/commands/Kconfig b/commands/Kconfig
index ebc9c7f2d0..3cf2d085f3 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -310,6 +310,28 @@ config CMD_BOOTM_SHOW_TYPE
depends on CMD_BOOTM
prompt "show image information"
+config CMD_BOOTM_VERBOSE
+ bool
+ prompt "bootm verbose support"
+ depends on CMD_BOOTM
+ help
+ support verbose bootm (-v switch)
+
+config CMD_BOOTM_INITRD
+ bool
+ prompt "bootm initrd support"
+ depends on CMD_BOOTM
+ help
+ support initrds in bootm
+
+config CMD_BOOTM_OFTREE_UIMAGE
+ bool
+ prompt "support passing oftree uImages"
+ depends on CMD_BOOTM
+ help
+ Support using oftree uImages. Without this only raw oftree
+ blobs can be used.
+
config CMD_IMINFO
bool
prompt "iminfo"
diff --git a/commands/bootm.c b/commands/bootm.c
index 265ad4637a..d9805866bd 100644
--- a/commands/bootm.c
+++ b/commands/bootm.c
@@ -39,202 +39,410 @@
#include <errno.h>
#include <boot.h>
#include <of.h>
+#include <libfdt.h>
#include <rtc.h>
#include <init.h>
+#include <of.h>
#include <magicvar.h>
#include <uncompress.h>
+#include <memory.h>
+#include <filetype.h>
#include <asm-generic/memory_layout.h>
-struct image_handle_data* image_handle_data_get_by_num(struct image_handle* handle, int num)
+static LIST_HEAD(handler_list);
+
+#ifdef CONFIG_CMD_BOOTM_INITRD
+static inline int bootm_initrd(struct image_data *data)
+{
+ return data->initrd ? 1 : 0;
+}
+#else
+static inline int bootm_initrd(struct image_data *data)
{
- if (!handle || num < 0 || num >= handle->nb_data_entries)
- return NULL;
+ return 0;
+}
+#endif
- return &handle->data_entries[num];
+int register_image_handler(struct image_handler *handler)
+{
+ list_add_tail(&handler->list, &handler_list);
+ return 0;
}
-int relocate_image(struct image_handle *handle, void *load_address)
+#define UIMAGE_SOME_ADDRESS (UIMAGE_INVALID_ADDRESS - 1)
+
+static int bootm_open_os_uimage(struct image_data *data)
{
- image_header_t *hdr = &handle->header;
- unsigned long len = image_get_size(hdr);
- struct image_handle_data *iha;
- void *data;
int ret;
- iha = image_handle_data_get_by_num(handle, 0);
- data = iha->data;
+ data->os = uimage_open(data->os_file);
+ if (!data->os)
+ return -EINVAL;
- switch (image_get_comp(hdr)) {
- case IH_COMP_NONE:
- if (load_address == data) {
- printf (" XIP ... ");
- } else {
- memmove(load_address, data, len);
- }
- break;
- default:
- printf (" Uncompressing ... ");
- ret = uncompress(data, len, NULL, NULL, load_address, NULL,
- uncompress_err_stdout);
- if (ret)
+ if (data->verify) {
+ ret = uimage_verify(data->os);
+ if (ret) {
+ printf("Checking data crc failed with %s\n",
+ strerror(-ret));
return ret;
- break;
+ }
+ }
+
+ uimage_print_contents(data->os);
+
+ if (data->os->header.ih_arch != IH_ARCH) {
+ printf("Unsupported Architecture 0x%x\n",
+ data->os->header.ih_arch);
+ return -EINVAL;
+ }
+
+ if (data->os_address == UIMAGE_SOME_ADDRESS)
+ data->os_address = data->os->header.ih_load;
+
+ if (data->os_address != UIMAGE_INVALID_ADDRESS) {
+ data->os_res = uimage_load_to_sdram(data->os, 0,
+ data->os_address);
+ if (!data->os_res)
+ return -ENOMEM;
}
return 0;
}
-EXPORT_SYMBOL(relocate_image);
-
-static LIST_HEAD(handler_list);
-int register_image_handler(struct image_handler *handler)
+static int bootm_open_initrd_uimage(struct image_data *data)
{
- list_add_tail(&handler->list, &handler_list);
+ int ret;
+
+ if (!data->initrd_file)
+ return 0;
+
+ if (strcmp(data->os_file, data->initrd_file)) {
+ data->initrd = uimage_open(data->initrd_file);
+ if (!data->initrd)
+ return -EINVAL;
+
+ if (data->verify) {
+ ret = uimage_verify(data->initrd);
+ if (ret) {
+ printf("Checking data crc failed with %s\n",
+ strerror(-ret));
+ }
+ }
+ uimage_print_contents(data->initrd);
+ } else {
+ data->initrd = data->os;
+ }
+
+ if (data->initrd_address == UIMAGE_SOME_ADDRESS)
+ data->initrd_address = data->initrd->header.ih_load;
+
+ if (data->initrd_address != UIMAGE_INVALID_ADDRESS) {
+ data->initrd_res = uimage_load_to_sdram(data->initrd,
+ data->initrd_num,
+ data->initrd_address);
+ if (!data->initrd_res)
+ return -ENOMEM;
+ }
+
return 0;
}
-/*
- * generate a image_handle from a multi_image
- * this image_handle can be freed by unmap_image
- */
-static struct image_handle *get_fake_image_handle(struct image_data *data, int num)
+#ifdef CONFIG_OFTREE
+static int bootm_open_oftree(struct image_data *data, char *oftree, int num)
{
- struct image_handle *handle;
- struct image_handle_data* iha;
- image_header_t *header;
+ enum filetype ft;
+ struct fdt_header *fdt;
+ int ret;
+ size_t size;
+
+ ft = file_name_detect_type(oftree);
+ if ((int)ft < 0)
+ return ft;
+
+ if (ft == filetype_uimage) {
+#ifdef CONFIG_CMD_BOOTM_OFTREE_UIMAGE
+ struct uimage_handle *of_handle;
+ int release = 0;
+
+ if (!strcmp(data->os_file, oftree)) {
+ of_handle = data->os;
+ } else if (!strcmp(data->initrd_file, oftree)) {
+ of_handle = data->initrd;
+ } else {
+ of_handle = uimage_open(oftree);
+ if (!of_handle)
+ return -ENODEV;
+ uimage_print_contents(of_handle);
+ release = 1;
+ }
+
+ fdt = uimage_load_to_buf(of_handle, num, &size);
+
+ if (release)
+ uimage_close(of_handle);
+#else
+ return -EINVAL;
+#endif
+ } else {
+ fdt = read_file(oftree, &size);
+ if (!fdt) {
+ perror("open");
+ return -ENODEV;
+ }
+ }
+
+ ft = file_detect_type(fdt);
+ if (ft != filetype_oftree) {
+ printf("%s is not a oftree but %s\n", oftree,
+ file_type_to_string(ft));
+ }
+
+ if (bootm_verbose(data))
+ printf("Loading oftree from '%s'\n", oftree);
+
+ fdt = xrealloc(fdt, size + 0x8000);
+ fdt_open_into(fdt, fdt, size + 0x8000);
+
+ if (!fdt) {
+ printf("unable to read %s\n", oftree);
+ return -ENODEV;
+ }
+
+ ret = of_fix_tree(fdt);
+ if (ret)
+ return ret;
- iha = image_handle_data_get_by_num(data->os, num);
+ if (bootm_verbose(data) > 1)
+ fdt_print(fdt, "/");
- handle = xzalloc(sizeof(struct image_handle));
- header = &handle->header;
- handle->data_entries = gen_image_handle_data(iha->data, iha->len);
- handle->nb_data_entries = 1;
- header->ih_size = cpu_to_uimage(iha->len);
- handle->data = handle->data_entries[0].data;
+ data->oftree = fdt;
- return handle;
+ return ret;
+}
+#endif
+
+static struct image_handler *bootm_find_handler(enum filetype filetype,
+ struct image_data *data)
+{
+ struct image_handler *handler;
+
+ list_for_each_entry(handler, &handler_list, list) {
+ if (filetype != filetype_uimage &&
+ handler->filetype == filetype)
+ return handler;
+ if (filetype == filetype_uimage &&
+ handler->ih_os == data->os->header.ih_os)
+ return handler;
+ }
+
+ return NULL;
+}
+
+static void bootm_image_name_and_no(char *name, int *no)
+{
+ char *at;
+
+ *no = 0;
+
+ at = strchr(name, '@');
+ if (!at)
+ return;
+
+ *at++ = 0;
+
+ *no = simple_strtoul(at, NULL, 10);
}
static int do_bootm(struct command *cmdtp, int argc, char *argv[])
{
- int opt;
- image_header_t *os_header;
- struct image_handle *os_handle = NULL;
+ int opt;
struct image_handler *handler;
struct image_data data;
- const char *initrdname = NULL;
int ret = 1;
+ enum filetype os_type, initrd_type = filetype_unknown;
+ char *oftree = NULL;
+ int fallback = 0;
memset(&data, 0, sizeof(struct image_data));
- data.verify = 1;
- data.initrd_address = ~0;
- while ((opt = getopt(argc, argv, "nr:L:")) > 0) {
+ data.initrd_address = UIMAGE_SOME_ADDRESS;
+ data.os_address = UIMAGE_SOME_ADDRESS;
+ data.verify = 0;
+ data.verbose = 0;
+
+ while ((opt = getopt(argc, argv, "cL:r:a:e:vo:f")) > 0) {
switch(opt) {
- case 'n':
- data.verify = 0;
+ case 'c':
+ data.verify = 1;
break;
+#ifdef CONFIG_CMD_BOOTM_INITRD
case 'L':
data.initrd_address = simple_strtoul(optarg, NULL, 0);
break;
case 'r':
- initrdname = optarg;
+ data.initrd_file = optarg;
+ break;
+#endif
+ case 'a':
+ data.os_address = simple_strtoul(optarg, NULL, 0);
+ break;
+ case 'e':
+ data.os_entry = simple_strtoul(optarg, NULL, 0);
+ break;
+ case 'v':
+ data.verbose++;
+ break;
+ case 'o':
+ oftree = optarg;
+ break;
+ case 'f':
+ fallback = 1;
break;
default:
break;
}
}
-#ifdef CONFIG_OFTREE
- data.oftree = of_get_fixed_tree();
-#endif
+ if (optind == argc)
+ return COMMAND_ERROR_USAGE;
+
+ data.os_file = argv[optind];
- if (optind == argc) {
- ret = COMMAND_ERROR_USAGE;
+ bootm_image_name_and_no(data.os_file, &data.os_num);
+
+ os_type = file_name_detect_type(data.os_file);
+ if ((int)os_type < 0) {
+ printf("could not open %s: %s\n", data.os_file,
+ strerror(-os_type));
goto err_out;
}
- os_handle = map_image(argv[optind], data.verify);
- if (!os_handle)
+ if (!fallback && os_type == filetype_unknown) {
+ printf("Unknown OS filetype (try -f)\n");
goto err_out;
- data.os = os_handle;
-
- os_header = &os_handle->header;
+ }
- if (image_get_arch(os_header) != IH_ARCH) {
- printf("Unsupported Architecture 0x%x\n",
- image_get_arch(os_header));
- goto err_out;
+ if (os_type == filetype_uimage) {
+ ret = bootm_open_os_uimage(&data);
+ if (ret) {
+ printf("loading initrd failed with %s\n",
+ strerror(-ret));
+ goto err_out;
+ }
}
- if (initrdname) {
- /* check for multi image @<num> */
- if (initrdname[0] == '@') {
- int num = simple_strtol(optarg + 1, NULL, 0);
+ if (bootm_initrd(&data)) {
+ bootm_image_name_and_no(data.initrd_file, &data.initrd_num);
- data.initrd = get_fake_image_handle(&data, num);
- } else {
- data.initrd = map_image(optarg, data.verify);
- }
- if (!data.initrd)
+ initrd_type = file_name_detect_type(data.initrd_file);
+ if ((int)initrd_type < 0) {
+ printf("could not open %s: %s\n", data.initrd_file,
+ strerror(-initrd_type));
goto err_out;
+ }
+ if (initrd_type == filetype_uimage) {
+ ret = bootm_open_initrd_uimage(&data);
+ if (ret) {
+ printf("loading initrd failed with %s\n",
+ strerror(-ret));
+ goto err_out;
+ }
+ }
}
- /*
- * 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...
- */
-
- puts ("OK\n");
-
- /*
- * FIXME: we do not check at all whether
- * - we will write the image to sdram
- * - we overwrite ourselves
- * - kernel and initrd overlap
- */
- ret = relocate_image(data.os, (void *)image_get_load(os_header));
- if (ret)
- goto err_out;
+ if (bootm_verbose(&data)) {
+ printf("\nLoading OS %s '%s'", file_type_to_string(os_type),
+ data.os_file);
+ if (os_type == filetype_uimage &&
+ data.os->header.ih_type == IH_TYPE_MULTI)
+ printf(", multifile image %d", data.os_num);
+ printf("\n");
+ if (data.os_res)
+ printf("OS image is at 0x%08x-0x%08x\n",
+ data.os_res->start,
+ data.os_res->start +
+ data.os_res->size - 1);
+ else
+ printf("OS image not yet relocated\n");
+
+ if (data.initrd_file) {
+ printf("Loading initrd %s '%s'",
+ file_type_to_string(initrd_type),
+ data.initrd_file);
+ if (initrd_type == filetype_uimage &&
+ data.initrd->header.ih_type == IH_TYPE_MULTI)
+ printf(", multifile image %d", data.initrd_num);
+ printf("\n");
+ if (data.initrd_res)
+ printf("initrd is at 0x%08x-0x%08x\n",
+ data.initrd_res->start,
+ data.initrd_res->start +
+ data.initrd_res->size - 1);
+ else
+ printf("initrd image not yet relocated\n");
+ }
+ }
- if (data.initrd) {
- if (data.initrd && data.initrd_address == ~0)
- data.initrd_address = uimage_to_cpu(data.initrd->header.ih_load);
+#ifdef CONFIG_OFTREE
+ if (oftree) {
+ int oftree_num;
- data.initrd_size = image_get_data_size(&data.initrd->header);
+ bootm_image_name_and_no(oftree, &oftree_num);
- ret = relocate_image(data.initrd, (void *)data.initrd_address);
+ ret = bootm_open_oftree(&data, oftree, oftree_num);
if (ret)
goto err_out;
}
-
- /* loop through the registered handlers */
- list_for_each_entry(handler, &handler_list, list) {
- if (image_get_os(os_header) == handler->image_type) {
- handler->bootm(&data);
- printf("handler returned!\n");
- goto err_out;
- }
+#endif
+ if (data.os_address == UIMAGE_SOME_ADDRESS)
+ data.os_address = UIMAGE_INVALID_ADDRESS;
+ if (data.initrd_address == UIMAGE_SOME_ADDRESS)
+ data.initrd_address = UIMAGE_INVALID_ADDRESS;
+
+ handler = bootm_find_handler(os_type, &data);
+ if (!handler) {
+ printf("no image handler found for image type %s\n",
+ file_type_to_string(os_type));
+ if (os_type == filetype_uimage)
+ printf("and os type: %d\n", data.os->header.ih_os);
+ goto err_out;
}
- printf("no image handler found for image type %d\n",
- image_get_os(os_header));
+ if (bootm_verbose(&data))
+ printf("Passing control to %s handler\n", handler->name);
+
+ ret = handler->bootm(&data);
+
+ printf("handler failed with %s\n", strerror(-ret));
err_out:
- if (os_handle)
- unmap_image(os_handle);
- if (data.initrd)
- unmap_image(data.initrd);
- return ret;
+ if (data.os_res)
+ release_sdram_region(data.os_res);
+ if (data.initrd_res)
+ release_sdram_region(data.initrd_res);
+ if (data.initrd && data.initrd != data.os)
+ uimage_close(data.initrd);
+ if (data.os)
+ uimage_close(data.os);
+ return 1;
}
BAREBOX_CMD_HELP_START(bootm)
BAREBOX_CMD_HELP_USAGE("bootm [OPTIONS] image\n")
BAREBOX_CMD_HELP_SHORT("Boot an application image.\n")
-BAREBOX_CMD_HELP_OPT ("-n", "Do not verify the image (speeds up boot process)\n")
+BAREBOX_CMD_HELP_OPT ("-c", "crc check uImage data\n")
+#ifdef CONFIG_CMD_BOOTM_INITRD
BAREBOX_CMD_HELP_OPT ("-r <initrd>","specify an initrd image\n")
-BAREBOX_CMD_HELP_OPT ("-L <load addr>","specify initrd load address")
+BAREBOX_CMD_HELP_OPT ("-L <load addr>","specify initrd load address\n")
+#endif
+BAREBOX_CMD_HELP_OPT ("-a <load addr>","specify os load address\n")
+BAREBOX_CMD_HELP_OPT ("-e <ofs>","entry point to the image relative to start (0)\n")
+#ifdef CONFIG_OFTREE
+BAREBOX_CMD_HELP_OPT ("-o <oftree>","specify oftree\n")
+#endif
+#ifdef CONFIG_CMD_BOOTM_VERBOSE
+BAREBOX_CMD_HELP_OPT ("-v","verbose\n")
+#endif
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(bootm)
@@ -245,13 +453,6 @@ BAREBOX_CMD_END
BAREBOX_MAGICVAR(bootargs, "Linux Kernel parameters");
-#ifdef CONFIG_BZLIB
-void bz_internal_error(int errcode)
-{
- printf ("BZIP2 internal error %d\n", errcode);
-}
-#endif /* CONFIG_BZLIB */
-
/**
* @file
* @brief Boot support for Linux