summaryrefslogtreecommitdiffstats
path: root/arch/arm/lib/bootm.c
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 /arch/arm/lib/bootm.c
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 'arch/arm/lib/bootm.c')
-rw-r--r--arch/arm/lib/bootm.c222
1 files changed, 207 insertions, 15 deletions
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 1de22bf81c..d8bb701c4a 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -11,6 +11,8 @@
#include <malloc.h>
#include <fcntl.h>
#include <errno.h>
+#include <sizes.h>
+#include <libbb.h>
#include <asm/byteorder.h>
#include <asm/setup.h>
@@ -18,33 +20,223 @@
#include <asm/armlinux.h>
#include <asm/system.h>
-static int do_bootm_linux(struct image_data *data)
+static int __do_bootm_linux(struct image_data *data, int swap)
{
- void (*theKernel)(int zero, int arch, void *params);
- image_header_t *os_header = &data->os->header;
+ unsigned long kernel;
+ unsigned long initrd_start = 0, initrd_size = 0;
+ struct memory_bank *bank;
+ unsigned long load_address;
+
+ if (data->os_res) {
+ load_address = data->os_res->start;
+ } else if (data->os_address != UIMAGE_INVALID_ADDRESS) {
+ load_address = data->os_address;
+ } else {
+ bank = list_first_entry(&memory_banks,
+ struct memory_bank, list);
+ load_address = bank->start + SZ_32K;
+ if (bootm_verbose(data))
+ printf("no os load address, defaulting to 0x%08lx\n",
+ load_address);
+ }
+
+ if (!data->os_res && data->os) {
+ data->os_res = uimage_load_to_sdram(data->os,
+ data->os_num, load_address);
+ if (!data->os_res)
+ return -ENOMEM;
+ }
+
+ if (!data->os_res) {
+ data->os_res = file_to_sdram(data->os_file, load_address);
+ if (!data->os_res)
+ return -ENOMEM;
+ }
+
+ kernel = data->os_res->start + data->os_entry;
+
+ if (data->initrd_file && data->initrd_address == UIMAGE_INVALID_ADDRESS) {
+ initrd_start = data->os_res->start + SZ_8M;
- theKernel = (void *)image_get_ep(os_header);
+ if (bootm_verbose(data)) {
+ printf("no initrd load address, defaulting to 0x%08lx\n",
+ initrd_start);
+ }
+ }
- debug("## Transferring control to Linux (at address 0x%p) ...\n",
- theKernel);
+ if (data->initrd) {
+ data->initrd_res = uimage_load_to_sdram(data->initrd,
+ data->initrd_num, initrd_start);
+ if (!data->initrd_res)
+ return -ENOMEM;
+ } else if (data->initrd_file) {
+ data->initrd_res = file_to_sdram(data->initrd_file, initrd_start);
+ if (!data->initrd_res)
+ return -ENOMEM;
+ }
- /* we assume that the kernel is in place */
- printf("\nStarting kernel %s...\n\n", data->initrd ? "with initrd " : "");
+ if (data->initrd_res) {
+ initrd_start = data->initrd_res->start;
+ initrd_size = data->initrd_res->size;
+ }
- start_linux((void *)theKernel, 0, data->initrd_address, data->initrd_size,
- data->oftree);
+ if (bootm_verbose(data)) {
+ printf("\nStarting kernel at 0x%08lx", kernel);
+ if (initrd_size)
+ printf(", initrd at 0x%08lx", initrd_start);
+ if (data->oftree)
+ printf(", oftree at 0x%p", data->oftree);
+ printf("...\n");
+ }
- return -1;
+ start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree);
+
+ reset_cpu(0);
+
+ return -ERESTARTSYS;
+}
+
+static int do_bootm_linux(struct image_data *data)
+{
+ return __do_bootm_linux(data, 0);
}
-static struct image_handler handler = {
+static struct image_handler uimage_handler = {
+ .name = "ARM Linux uImage",
.bootm = do_bootm_linux,
- .image_type = IH_OS_LINUX,
+ .filetype = filetype_uimage,
+ .ih_os = IH_OS_LINUX,
};
-static int armlinux_register_image_handler(void)
+static struct image_handler rawimage_handler = {
+ .name = "ARM raw image",
+ .bootm = do_bootm_linux,
+ .filetype = filetype_unknown,
+};
+
+struct zimage_header {
+ u32 unused[9];
+ u32 magic;
+ u32 start;
+ u32 end;
+};
+
+#define ZIMAGE_MAGIC 0x016F2818
+
+static int do_bootz_linux(struct image_data *data)
+{
+ int fd, ret, swap = 0;
+ struct zimage_header __header, *header;
+ void *zimage;
+ u32 end;
+ unsigned long load_address = data->os_address;
+
+ if (load_address == UIMAGE_INVALID_ADDRESS) {
+ struct memory_bank *bank = list_first_entry(&memory_banks,
+ struct memory_bank, list);
+ data->os_address = bank->start + SZ_8M;
+ if (bootm_verbose(data))
+ printf("no os load address, defaulting to 0x%08lx\n",
+ load_address);
+ }
+
+ fd = open(data->os_file, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ header = &__header;
+ ret = read(fd, header, sizeof(*header));
+ if (ret < sizeof(*header)) {
+ printf("could not read %s\n", data->os_file);
+ goto err_out;
+ }
+
+ switch (header->magic) {
+ case swab32(ZIMAGE_MAGIC):
+ swap = 1;
+ /* fall through */
+ case ZIMAGE_MAGIC:
+ break;
+ default:
+ printf("invalid magic 0x%08x\n", header->magic);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ end = header->end;
+
+ if (swap)
+ end = swab32(end);
+
+ data->os_res = request_sdram_region("zimage", load_address, end);
+ if (!data->os_res) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ zimage = (void *)data->os_res->start;
+
+ memcpy(zimage, header, sizeof(*header));
+
+ ret = read_full(fd, zimage + sizeof(*header), end - sizeof(*header));
+ if (ret < 0)
+ goto err_out;
+ if (ret < end - sizeof(*header)) {
+ printf("premature end of image\n");
+ ret = -EIO;
+ goto err_out;
+ }
+
+ if (swap) {
+ void *ptr;
+ for (ptr = zimage; ptr < zimage + end; ptr += 4)
+ *(u32 *)ptr = swab32(*(u32 *)ptr);
+ }
+
+ return __do_bootm_linux(data, swap);
+
+err_out:
+ close(fd);
+
+ return ret;
+}
+
+static struct image_handler zimage_handler = {
+ .name = "ARM zImage",
+ .bootm = do_bootz_linux,
+ .filetype = filetype_arm_zimage,
+};
+
+static int do_bootm_barebox(struct image_data *data)
{
- return register_image_handler(&handler);
+ void (*barebox)(void);
+
+ barebox = read_file(data->os_file, NULL);
+ if (!barebox)
+ return -EINVAL;
+
+ shutdown_barebox();
+
+ barebox();
+
+ reset_cpu(0);
}
+static struct image_handler barebox_handler = {
+ .name = "ARM barebox",
+ .bootm = do_bootm_barebox,
+ .filetype = filetype_arm_barebox,
+};
+
+static int armlinux_register_image_handler(void)
+{
+ register_image_handler(&barebox_handler);
+ register_image_handler(&uimage_handler);
+ register_image_handler(&rawimage_handler);
+ register_image_handler(&zimage_handler);
+
+ return 0;
+}
late_initcall(armlinux_register_image_handler);