[U-Boot] [PATCH] BOOT: Add "bootz" command to boot Linux zImage

This command boots Linux zImage from where the zImage is loaded to. Passing initrd and fdt is supported.
Tested on PXA270 based Voipac PXA270.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Tom Warren TWarren@nvidia.com Cc: albert.u.boot@aribaud.net Cc: afleming@gmail.com, Cc: Simon Glass sjg@chromium.org, Cc: Stephen Warren swarren@nvidia.com --- common/Makefile | 1 + common/cmd_bootz.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 0 deletions(-) create mode 100644 common/cmd_bootz.c
diff --git a/common/Makefile b/common/Makefile index 1b672ad..1ddf77a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -42,6 +42,7 @@ COBJS-y += xyzModem.o # core command COBJS-y += cmd_boot.o COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o +COBJS-$(CONFIG_CMD_BOOTZ) += cmd_bootz.o COBJS-y += cmd_help.o COBJS-y += cmd_nvedit.o COBJS-y += cmd_version.o diff --git a/common/cmd_bootz.c b/common/cmd_bootz.c new file mode 100644 index 0000000..bb35209 --- /dev/null +++ b/common/cmd_bootz.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <watchdog.h> +#include <command.h> +#include <image.h> +#include <malloc.h> +#include <u-boot/zlib.h> +#include <bzlib.h> +#include <environment.h> +#include <lmb.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> + +#if defined(CONFIG_CMD_USB) +#include <usb.h> +#endif + +#if defined(CONFIG_SYS_HUSH_PARSER) +#include <hush.h> +#endif + +#if defined(CONFIG_OF_LIBFDT) +#include <fdt.h> +#include <libfdt.h> +#include <fdt_support.h> +#endif + +#define IH_INITRD_ARCH IH_ARCH_DEFAULT + +extern int do_bootm_linux(int flag, int argc, char *argv[], + bootm_headers_t *images); + +static void bootm_start_lmb(bootm_headers_t *images) +{ +#ifdef CONFIG_LMB + ulong mem_start; + phys_size_t mem_size; + + lmb_init(&images->lmb); + + mem_start = getenv_bootm_low(); + mem_size = getenv_bootm_size(); + + lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size); + + arch_lmb_reserve(&images->lmb); + board_lmb_reserve(&images->lmb); +#else +# define lmb_reserve(lmb, base, size) +#endif +} + +static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + bootm_headers_t *images) +{ + int ret; + + memset(images, 0, sizeof(bootm_headers_t)); + + bootm_start_lmb(images); + + /* Setup Linux kernel zImage entry point */ + if (argc < 2) { + images->ep = load_addr; + debug("* kernel: default image load address = 0x%08lx\n", + load_addr); + } else { + images->ep = simple_strtoul(argv[1], NULL, 16); + debug("* kernel: cmdline image address = 0x%08lx\n", + images->ep); + } + + lmb_reserve(&images->lmb, images->ep, 16 * 1024*1024); + + /* 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, 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; +} + +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong iflag; + bootm_headers_t images; + + 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... + */ + iflag = disable_interrupts(); + +#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 + 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; +} + +U_BOOT_CMD( + bootz, CONFIG_SYS_MAXARGS, 1, do_bootz, + "boot Linux zImage image from memory", + "[addr [initrd] [fdt]]\n - boot Linux zImage stored in memory\n" + "\tThe argument 'initrd' is optional and specifies the address\n" + "\tof the initrd in memory.\n" +#if defined(CONFIG_OF_LIBFDT) + "\tWhen booting a Linux kernel which requires a flat device-tree\n" + "\ta third argument is required which is the address of the\n" + "\tdevice-tree blob. To boot that kernel without an initrd image,\n" + "\tuse a '-' for the second argument. If you do not pass a third\n" + "\ta bd_info struct will be passed instead\n" +#endif +);

This command boots Linux zImage from where the zImage is loaded to. Passing initrd and fdt is supported.
Tested on PXA270 based Voipac PXA270.
Signed-off-by: Marek Vasut marek.vasut@gmail.com Cc: Tom Warren TWarren@nvidia.com Cc: albert.u.boot@aribaud.net Cc: afleming@gmail.com, Cc: Simon Glass sjg@chromium.org, Cc: Stephen Warren swarren@nvidia.com --- common/Makefile | 1 + common/cmd_bootz.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 0 deletions(-) create mode 100644 common/cmd_bootz.c
V2: Use CONFIG_BOOTZ_MAX_KERNEL_LMB_SIZE to reserve kernel LMB
diff --git a/common/Makefile b/common/Makefile index 1b672ad..1ddf77a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -42,6 +42,7 @@ COBJS-y += xyzModem.o # core command COBJS-y += cmd_boot.o COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o +COBJS-$(CONFIG_CMD_BOOTZ) += cmd_bootz.o COBJS-y += cmd_help.o COBJS-y += cmd_nvedit.o COBJS-y += cmd_version.o diff --git a/common/cmd_bootz.c b/common/cmd_bootz.c new file mode 100644 index 0000000..fc98464 --- /dev/null +++ b/common/cmd_bootz.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2011 Marek Vasut marek.vasut@gmail.com + * + * Based on code: + * (C) Copyright 2000-2009 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 <watchdog.h> +#include <command.h> +#include <image.h> +#include <malloc.h> +#include <u-boot/zlib.h> +#include <bzlib.h> +#include <environment.h> +#include <lmb.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> + +#if defined(CONFIG_CMD_USB) +#include <usb.h> +#endif + +#if defined(CONFIG_SYS_HUSH_PARSER) +#include <hush.h> +#endif + +#if defined(CONFIG_OF_LIBFDT) +#include <fdt.h> +#include <libfdt.h> +#include <fdt_support.h> +#endif + +#define IH_INITRD_ARCH IH_ARCH_DEFAULT + +extern int do_bootm_linux(int flag, int argc, char *argv[], + bootm_headers_t *images); + +static void bootm_start_lmb(bootm_headers_t *images) +{ +#ifdef CONFIG_LMB + ulong mem_start; + phys_size_t mem_size; + + lmb_init(&images->lmb); + + mem_start = getenv_bootm_low(); + mem_size = getenv_bootm_size(); + + lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size); + + arch_lmb_reserve(&images->lmb); + board_lmb_reserve(&images->lmb); +#else +# define lmb_reserve(lmb, base, size) +#endif +} + +static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], + bootm_headers_t *images) +{ + int ret; + + memset(images, 0, sizeof(bootm_headers_t)); + + bootm_start_lmb(images); + + /* Setup Linux kernel zImage entry point */ + if (argc < 2) { + images->ep = load_addr; + debug("* kernel: default image load address = 0x%08lx\n", + load_addr); + } else { + images->ep = simple_strtoul(argv[1], NULL, 16); + debug("* kernel: cmdline image address = 0x%08lx\n", + images->ep); + } + + lmb_reserve(&images->lmb, images->ep, CONFIG_BOOTZ_MAX_KERNEL_LMB_SIZE); + + /* 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, 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; +} + +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + ulong iflag; + bootm_headers_t images; + + 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... + */ + iflag = disable_interrupts(); + +#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 + 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; +} + +U_BOOT_CMD( + bootz, CONFIG_SYS_MAXARGS, 1, do_bootz, + "boot Linux zImage image from memory", + "[addr [initrd] [fdt]]\n - boot Linux zImage stored in memory\n" + "\tThe argument 'initrd' is optional and specifies the address\n" + "\tof the initrd in memory.\n" +#if defined(CONFIG_OF_LIBFDT) + "\tWhen booting a Linux kernel which requires a flat device-tree\n" + "\ta third argument is required which is the address of the\n" + "\tdevice-tree blob. To boot that kernel without an initrd image,\n" + "\tuse a '-' for the second argument. If you do not pass a third\n" + "\ta bd_info struct will be passed instead\n" +#endif +);

Marek Vasut wrote at Friday, November 11, 2011 7:51 PM:
This command boots Linux zImage from where the zImage is loaded to. Passing initrd and fdt is supported.
Marek, this looks pretty neat. A few general questions though:
1) I believe the zImage format is ARCH-specific. I'm not sure that on non-ARM ARCHs, you just start executing at the start of the zImage. Should this function be somehow disabled on non-ARM until something explicit is done about that?
2) Should bootz_start() validate it was passed a valid zImage, by checking the magic value in the header?
3) boot_get_ramdisk() only accepts uImage (legacy or FIT). Can/should it be enhanced to accept raw ramdisk images?
4) Is it safe to assume that do_bootm_linux() only cares about images->ep and nothing else for the kernel? I know it's coded that way right now, but I wonder if someone might refactor bootm and forget about bootz and change this assumption. I guess this is OK though...
I don't have any other specific comments on the code.
You may want to CC everyone else involved in the IH_TYPE_KERNEL_NOLOAD discussion - I imagine they'll all be interested in this too.
-- nvpublic

Marek Vasut wrote at Friday, November 11, 2011 7:51 PM:
This command boots Linux zImage from where the zImage is loaded to. Passing initrd and fdt is supported.
Marek, this looks pretty neat. A few general questions though:
- I believe the zImage format is ARCH-specific. I'm not sure that on
non-ARM ARCHs, you just start executing at the start of the zImage. Should this function be somehow disabled on non-ARM until something explicit is done about that?
Well zImage contains the decompressor which handles the proper placement of the kernel. Therefore there is only the catch the user must not be an idiot and must load the kernel at the correct address himself.
- Should bootz_start() validate it was passed a valid zImage, by checking
the magic value in the header?
Sounds good.
- boot_get_ramdisk() only accepts uImage (legacy or FIT). Can/should it
be enhanced to accept raw ramdisk images?
Certainly, that'd help. Are you willing to look into that?
- Is it safe to assume that do_bootm_linux() only cares about images->ep
and nothing else for the kernel? I know it's coded that way right now, but I wonder if someone might refactor bootm and forget about bootz and change this assumption. I guess this is OK though...
Yes, this is valid point. We should be very careful about this. So suggestions how to handle this ?
I don't have any other specific comments on the code.
You may want to CC everyone else involved in the IH_TYPE_KERNEL_NOLOAD discussion - I imagine they'll all be interested in this too.
Sure.
-- nvpublic

Marek Vasut wrote at Monday, November 14, 2011 12:42 PM:
Marek Vasut wrote at Friday, November 11, 2011 7:51 PM:
This command boots Linux zImage from where the zImage is loaded to. Passing initrd and fdt is supported.
Marek, this looks pretty neat. A few general questions though:
- I believe the zImage format is ARCH-specific. I'm not sure that on
non-ARM ARCHs, you just start executing at the start of the zImage. Should this function be somehow disabled on non-ARM until something explicit is done about that?
Well zImage contains the decompressor which handles the proper placement of the kernel. Therefore there is only the catch the user must not be an idiot and must load the kernel at the correct address himself.
My point is that since the zImage format is ARCH-specific, is it always true that to boot a zImage, you always jump directly to offset 0 of that image, or are there other cases to consider?
In particular, looking at arch/x86/boot/header.S, which is what I believe is at the start of an x86 (b)zImage, if you jump to offset zero, you'll end up seeing a message stating that booting from floppy isn't support. Instead, I /think/ you need to jump to offset 512. Similarly, it looks like the magic number for an x86 (b)zImage is at a different offset within the image, and has a different value.
Now, all of that can be catered for pretty easily by bootz with just a few ifdefs in the future, but given the existing implementation possibly only works for ARM, it seems sensible to prevent usage on non-ARM for now.
- boot_get_ramdisk() only accepts uImage (legacy or FIT). Can/should it
be enhanced to accept raw ramdisk images?
Certainly, that'd help. Are you willing to look into that?
I would prefer not to commit to this; I'm pretty swamped. Unfortunately, bootm (plus IH_TYPE_KERNEL_NOLOAD) works fine for me, so I'm not terribly motivated here.
- Is it safe to assume that do_bootm_linux() only cares about images->ep
and nothing else for the kernel? I know it's coded that way right now, but I wonder if someone might refactor bootm and forget about bootz and change this assumption. I guess this is OK though...
Yes, this is valid point. We should be very careful about this. So suggestions how to handle this ?
Well, just keeping an eye out for any bootm-related changes would be simplest.
One way to enforce this might be to change each ARCH's implementation of do_bootm_linux() to accept the specific values it needs right now. This would document exactly what information was required. You'd also need a shim function to convert from prototype boot_os_fn (see common/cmd_bootm.c's boot_os[] array) to this new prototype. Have cmd_bootz() call the specific function directly instead of the shim (so passing explicit data instead of the images array). With that in place, any change to do_bootm_linux() would fail to compile unless cmd_bootz() was adjusted appropriately.
participants (2)
-
Marek Vasut
-
Stephen Warren