summaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/arm/lib/bootm.c222
-rw-r--r--arch/blackfin/lib/blackfin_linux.c12
-rw-r--r--arch/nios2/lib/bootm.c11
-rw-r--r--arch/ppc/lib/ppclinux.c16
4 files changed, 230 insertions, 31 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);
diff --git a/arch/blackfin/lib/blackfin_linux.c b/arch/blackfin/lib/blackfin_linux.c
index 9da9ec4e58..458d1b180b 100644
--- a/arch/blackfin/lib/blackfin_linux.c
+++ b/arch/blackfin/lib/blackfin_linux.c
@@ -34,6 +34,7 @@
#include <asm/byteorder.h>
#include <asm/cpu.h>
#include <asm/blackfin.h>
+#include <errno.h>
#include <init.h>
#include <boot.h>
@@ -44,10 +45,11 @@ static int do_bootm_linux(struct image_data *idata)
int (*appl)(char *cmdline);
const char *cmdline = getenv("bootargs");
char *cmdlinedest = (char *) CMD_LINE_ADDR;
- struct image_handle *os_handle = idata->os;
- image_header_t *os_header = &os_handle->header;
- appl = (int (*)(char *))image_get_ep(os_header);
+ if (!idata->os_res)
+ return -EINVAL;
+
+ appl = (void *)(idata->os_address + idata->os_entry);
printf("Starting Kernel at 0x%p\n", appl);
icache_disable();
@@ -63,8 +65,10 @@ static int do_bootm_linux(struct image_data *idata)
}
static struct image_handler handler = {
+ .name = "Blackfin Linux",
.bootm = do_bootm_linux,
- .image_type = IH_OS_LINUX,
+ .filetype = filetype_uimage,
+ .ih_os = IH_OS_LINUX,
};
static int bfinlinux_register_image_handler(void)
diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c
index b5b344f499..1cd43c81af 100644
--- a/arch/nios2/lib/bootm.c
+++ b/arch/nios2/lib/bootm.c
@@ -31,17 +31,20 @@
#include <environment.h>
#include <init.h>
#include <boot.h>
+#include <errno.h>
#include <asm/cache.h>
#define NIOS_MAGIC 0x534f494e /* enable command line and initrd passing */
static int do_bootm_linux(struct image_data *idata)
{
- image_header_t *os_header = &idata->os->header;
void (*kernel)(int, int, int, const char *);
const char *commandline = getenv ("bootargs");
- kernel = (void (*)(int, int, int, const char *))ntohl(os_header->ih_ep);
+ if (!idata->os_res)
+ return -EINVAL;
+
+ kernel = (void *)(idata->os_address + idata->os_entry);
/* kernel parameters passing
* r4 : NIOS magic
@@ -63,8 +66,10 @@ static int do_bootm_linux(struct image_data *idata)
}
static struct image_handler handler = {
+ .name = "NIOS2 Linux",
.bootm = do_bootm_linux,
- .image_type = IH_OS_LINUX,
+ .filetype = filetype_uimage,
+ .ih_os = IH_OS_LINUX,
};
int nios2_register_image_handler(void)
diff --git a/arch/ppc/lib/ppclinux.c b/arch/ppc/lib/ppclinux.c
index f7d3950603..3c1b3fa006 100644
--- a/arch/ppc/lib/ppclinux.c
+++ b/arch/ppc/lib/ppclinux.c
@@ -11,18 +11,15 @@
#include <errno.h>
#include <fs.h>
-#ifdef CONFIG_OF_FLAT_TREE
-#include <ft_build.h>
-#endif
-extern bd_t *bd;
-
static int do_bootm_linux(struct image_data *data)
{
void (*kernel)(void *, void *, unsigned long,
unsigned long, unsigned long);
- struct image_header *os_header = &data->os->header;
- kernel = (void *)image_get_ep(os_header);
+ if (!data->os_res)
+ return -EINVAL;
+
+ kernel = (void *)(data->os_address + data->os_entry);
/*
* Linux Kernel Parameters (passing device tree):
@@ -41,8 +38,10 @@ static int do_bootm_linux(struct image_data *data)
}
static struct image_handler handler = {
+ .name = "PowerPC Linux",
.bootm = do_bootm_linux,
- .image_type = IH_OS_LINUX,
+ .filetype = filetype_uimage,
+ .ih_os = IH_OS_LINUX,
};
static int ppclinux_register_image_handler(void)
@@ -51,4 +50,3 @@ static int ppclinux_register_image_handler(void)
}
late_initcall(ppclinux_register_image_handler);
-