[U-Boot] U-boot SPL direct Linux boot

Hi List,
for my bachelor thesis I will implement a direct Linux boot from U-Boot SPL. My current plan is to utilize do_bootm_[OS].
Simplest solution is to direct boot Linux/other OS and just boot u-boot when a key is pressed. In addition i will also have some tests (header check/CRC) - if they fail start u-boot.
IMHO this may also be of interest for the new SPL architecture.
Are there already implementations I am not aware of? Any comments on what I should also add? Problems I may not see?
Regards Simon

Hello Simon,
Simon Schwarz wrote:
for my bachelor thesis I will implement a direct Linux boot from U-Boot SPL. My current plan is to utilize do_bootm_[OS].
Simplest solution is to direct boot Linux/other OS and just boot u-boot when a key is pressed. In addition i will also have some tests (header check/CRC) - if they fail start u-boot.
IMHO this may also be of interest for the new SPL architecture.
Are there already implementations I am not aware of? Any comments on what I should also add? Problems I may not see?
I tried this on an davinci dm368 based board (not in mainline yet, but patches for the board support coming soon), with the following patch:
From 684cb207b14585f9d83f2c4c6f72b5b8bd4fd1a0 Mon Sep 17 00:00:00 2001
From: Heiko Schocher hs@denx.de Date: Mon, 30 May 2011 08:26:10 +0200 Subject: [PATCH] boot an arm linux kernel direct from nand_spl code
you need 2 images in Flash:
- Linux image @CONFIG_SYS_NAND_LINUX_OFFS - ATAG image @CONFIG_SYS_NAND_ATAG_OFFS
ATAG image is just a copy from the ATAG info u-boot created, before booting an arm linux kernel ...
ToDo/suggestions:
- we should define a struct, which contains the 3 values offset, size, destination, so we can create a "nand_load_list" which can contain n entries, that could be processed in a while loop ... so no need for the CONFIG_SYS_BOOT_LINUX define ;-)
For example: { {CONFIG_SYS_NAND_LINUX_OFFS, CONFIG_SYS_NAND_LINUX_SIZE, CONFIG_SYS_NAND_LINUX_DST}, {CONFIG_SYS_NAND_ATAG_OFFS, CONFIG_SYS_NAND_ATAG_SIZE, CONFIG_SYS_NAND_ATAG_DST}, {} } nand_load_list_linux;
{ {CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, CONFIG_SYS_NAND_U_BOOT_DST}, #ifdef CONFIG_NAND_ENV_DST {CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, CONFIG_NAND_ENV_DST}, #ifdef CONFIG_ENV_OFFSET_REDUND {CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE}, #endif #endif {} }nand_load_list_uboot;
in nand_boot() we can now for example get the state from a GPIO pin, and boot "linux/atag" or the "u-boot/env/env-red" case, or others (for example "powerpclinux/dtb")
if (gpio == bootlinux) nand_list = &nand_load_list_linux; else nand_list = &nand_load_list_uboot while (nand_list) { nand_load((&nand_info, nand_list->off, nand_list->size, nand_list->dest); }
Signed-off-by: Heiko Schocher hs@denx.de --- diff --git a/include/configs/board_config.h b/include/configs/board_config.h index fed8ac1..6f304f5 100644 --- a/include/configs/board_config.h +++ b/include/configs/board_config.h @@ -342,6 +342,19 @@ was ist das? * and in nand_spl mode cpu setup is * done in board_init_f from c code. */ +#define CONFIG_SYS_BOOT_LINUX +#if defined(CONFIG_SYS_BOOT_LINUX) +#define CONFIG_SYS_NAND_LINUX_OFFS 0x400000 +#define CONFIG_SYS_NAND_LINUX_SIZE 0x240000 +#define CONFIG_SYS_NAND_LINUX_DST 0x80008000 + +#define CONFIG_SYS_NAND_ATAG_OFFS (CONFIG_SYS_NAND_LINUX_OFFS + CONFIG_SYS_NAND_LINUX_SIZE) +#define CONFIG_SYS_NAND_ATAG_SIZE (CONFIG_SYS_NAND_PAGE_SIZE) +#define CONFIG_SYS_NAND_ATAG_DST (0x80000100) + +#define CONFIG_SYS_NAND_SPL_MACHID MACH_TYPE_DAVINCI_DM365_EVM +#endif +
/* for UBL header */
diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index c0e56e7..f78b39d 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -242,6 +239,8 @@ static int nand_load(struct mtd_info *mtd, unsigned int offs, nand_read_page(mtd, block, page, dst); dst += CONFIG_SYS_NAND_PAGE_SIZE; page++; + if (uboot_size == CONFIG_SYS_NAND_PAGE_SIZE) + break; }
page = 0; @@ -280,6 +279,30 @@ void nand_boot(void) if (nand_chip.select_chip) nand_chip.select_chip(&nand_info, 0);
+#if defined(CONFIG_SYS_BOOT_LINUX) + { + __attribute__((noreturn)) void (*kernel_entry)(int zero, int arch, uint params); + + kernel_entry = (void (*)(int, int, uint))CONFIG_SYS_NAND_LINUX_DST; + /* + * Load Linux image from NAND into RAM + */ + puts("load Linux image ...\n"); + ret = nand_load(&nand_info, CONFIG_SYS_NAND_LINUX_OFFS, CONFIG_SYS_NAND_LINUX_SIZE, + (uchar *)CONFIG_SYS_NAND_LINUX_DST); + /* + * Load ATAG image from NAND into RAM + */ + puts("load ATAG image ...\n"); + ret = nand_load(&nand_info, CONFIG_SYS_NAND_ATAG_OFFS, CONFIG_SYS_NAND_ATAG_SIZE, + (uchar *)CONFIG_SYS_NAND_ATAG_DST); + + + puts("booting Linux ....\n"); + (kernel_entry)(0, CONFIG_SYS_NAND_SPL_MACHID, CONFIG_SYS_NAND_ATAG_DST); + } +#else + /* * Load U-Boot image from NAND into RAM */ @@ -304,4 +327,5 @@ void nand_boot(void) */ uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; (*uboot)(); +#endif }

thanks Heiko! That seems like half of the work :)
- we should define a struct, which contains the 3 values
offset, size, destination, so we can create a "nand_load_list" which can contain n entries, that could be processed in a while loop ... so no need for the CONFIG_SYS_BOOT_LINUX define ;-)
I would also add some kind of CRC to check the integrity of the image?
Another question is if we not just use the uImage format provided by mkImage. This IMHO should include all this (except the offset) but then we have to read the first NAND-page (or what ever medium) to get these values which presumably means a significant slow-down. But then we can update the image without updating u-boot what i would consider important for non-dev devices.
Regards Simon

Dear Simon Schwarz,
In message BANLkTinCM+qWU_D50LJgf6Am=7GgoErh4g@mail.gmail.com you wrote:
- we should define a struct, which contains the 3 values
offset, size, destination, so we can create a "nand_load_list" which can contain n entries, that could be processed in a while loop ... so no need for the CONFIG_SYS_BOOT_LINUX define ;-)
I would also add some kind of CRC to check the integrity of the image?
If you add this, then please make sure to make it optional. Keep in mind that there are systems where the SPL code has to be really small (like 4 or even 2 KiB).
Another question is if we not just use the uImage format provided by mkImage. This IMHO should include all this (except the offset) but then we have to read the first NAND-page (or what ever medium) to get these values which presumably means a significant slow-down. But then we can update the image without updating u-boot what i would consider important for non-dev devices.
Reading an uImage and just skipping the 64 byte image header is definitely an option.
Please keep the design simple - adding bells and whistles can be done later, if there is room and time for it.
Best regards,
Wolfgang Denk

Ok, topic ATAGS: I see three ways doing ATAGS init for SPL: 1. use bootm.c which means init bd correctly and add a bunch of #ifdef CONFIG_PRELOADER to it - maybe also to some others i don't have on the radar yet. 2. Have ATAGS config in board config file and init it at compile time 3. Doing it like Heiko and copy the ATAGS config done by u-boot
My favourite here is number 2 because it would be faster than 1 and won't take so much work and won't clutter the standard u-boot code with #ifdefs. Also it is simpler to use than 3. the downside is that the section for ATAGS config would be huge and the code could diverge over time...
Comments?
Regards Simon

Hi Simon,
Ok, topic ATAGS: I see three ways doing ATAGS init for SPL:
- use bootm.c which means init bd correctly and add a bunch of #ifdef
CONFIG_PRELOADER to it - maybe also to some others i don't have on the radar yet. 2. Have ATAGS config in board config file and init it at compile time 3. Doing it like Heiko and copy the ATAGS config done by u-boot
My favourite here is number 2 because it would be faster than 1 and won't take so much work and won't clutter the standard u-boot code with #ifdefs. Also it is simpler to use than 3. the downside is that the section for ATAGS config would be huge and the code could diverge over time...
Comments?
Just a probably dumb side question, but will ATAGS be deprecated once we have the flat device tree also on ARM? As I understand, fdt is certainly the way to go forward, so maybe we can already start with that? In that case, the fdt blob will be another binary blob to be passed to the kernel and as such should be independant of U-Boot. So ideally in U-Boot we have a pointer to the fdt but the fdt itself can be updated independantly.
Just a thought. Detlev

Hi Detlev,
Just a probably dumb side question, but will ATAGS be deprecated once we have the flat device tree also on ARM? As I understand, fdt is certainly the way to go forward, so maybe we can already start with that? In that case, the fdt blob will be another binary blob to be passed to the kernel and as such should be independant of U-Boot. So ideally in U-Boot we have a pointer to the fdt but the fdt itself can be updated independantly.
I also thought about that. But I actually thought that FDT support for ARM isn't ready yet - although I saw much code for it while I worked on ATAGS. How is the FDT-state for ARM? If it is already usable I would be happy to adapt it. But if not I would prefer to stay with ATAGS (as I have a tight schedule for my BA thesis).
Thx for your comment!
Regards Simon

Addition: As I read a bit about FDT it does not replace ATAGS (http://elinux.org/Device_Trees) - it is more a supplement to it. So it would not harm to implement minimal ATAGS support and later add the FDT to it.
I started a prototype for ATAGS creation by modifying bootm.c - which seems (so long) not be too hard. If this works and doesn't add too much overhead FDT support is not that much a problem IMHO.
Regards Simon
(Sorry Detlev for the repost - forgot the ML...)

On Fri, Jul 1, 2011 at 10:42 AM, Simon Schwarz simonschwarzcor@googlemail.com wrote:
Addition: As I read a bit about FDT it does not replace ATAGS (http://elinux.org/Device_Trees) - it is more a supplement to it. So it would not harm to implement minimal ATAGS support and later add the FDT to it.
That was true in an early prototype, but it is not actually true anymore. Passing a DT replaces ATAGs on arm now, and that code is in mainline.
I started a prototype for ATAGS creation by modifying bootm.c - which seems (so long) not be too hard. If this works and doesn't add too much overhead FDT support is not that much a problem IMHO.
Regards Simon
(Sorry Detlev for the repost - forgot the ML...) _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Thanks for all the responses!
I decided that the approach from Heiko really is the best/simplest one.
Later I will release a first patch as RFC for how saving of the boot-params could be done.
With the implementation in the SPL boot I will wait until Aneesh V finished his work on OMAP4/SPL.
Regards Simon

Dear Simon Schwarz,
In message BANLkTimwHUopgQ4FLw4=ZmxYqHS1kH4kTA@mail.gmail.com you wrote:
I also thought about that. But I actually thought that FDT support for ARM isn't ready yet - although I saw much code for it while I worked on ATAGS. How is the FDT-state for ARM? If it is already usable I would be happy to adapt it. But if not I would prefer to stay with ATAGS (as I have a tight schedule for my BA thesis).
FDT support has been stable for some time on a (growing) number of reference boards. See Grant Likely's tree for reference.
Speaking just for us (DENX): we will probably not do any new ARM Linux port without FDT support any more.
Best regards,
Wolfgang Denk

Dear Detlev,
In message m21uyann8m.fsf@ohwell.denx.de you wrote:
Just a probably dumb side question, but will ATAGS be deprecated once we have the flat device tree also on ARM? As I understand, fdt is certainly
This is our understanding. For DT aware boards, no ATAGS are needed /used any more.
the way to go forward, so maybe we can already start with that? In that case, the fdt blob will be another binary blob to be passed to the kernel and as such should be independant of U-Boot. So ideally in U-Boot we have a pointer to the fdt but the fdt itself can be updated independantly.
Right. That was the idea behind Heikos code: we don't actually care what the kernel expects, we just pass it a binary blob and assume it will understand it. This may be a blob with ATAGs, or a blob with a DT - only the kernel needs to know, the code in the SPL remains lean and flexible.
Best regards,
Wolfgang Denk

On 07/01/11 12:17, Simon Schwarz wrote:
Ok, topic ATAGS: I see three ways doing ATAGS init for SPL:
- use bootm.c which means init bd correctly and add a bunch of #ifdef
CONFIG_PRELOADER to it - maybe also to some others i don't have on the radar yet.
While this is not clean, it might work good.
- Have ATAGS config in board config file and init it at compile time
This is a problematic approach, because memory size, board revision, serial number and may be some others are only known in runtime.
- Doing it like Heiko and copy the ATAGS config done by u-boot
This one is probably the most clean way.
My favourite here is number 2 because it would be faster than 1 and won't take so much work and won't clutter the standard u-boot code with #ifdefs. Also it is simpler to use than 3. the downside is that the section for ATAGS config would be huge and the code could diverge over time...
Regarding the device tree on ARM, it is still not fully functional. Nevertheless, currently there is an attempt ([1] and [2]) to make kernel work with both, device tree and ATAGS and if I understood correctly, the ATAGS will have precedence over the DT, so closed source boot loaders will still work.
[1] - http://www.spinics.net/lists/arm-kernel/msg128172.html [2] - http://www.spinics.net/lists/arm-kernel/msg129270.html

Thanks for your feedback Igor!
2011/7/1 Igor Grinberg grinberg@compulab.co.il:
On 07/01/11 12:17, Simon Schwarz wrote:
Ok, topic ATAGS: I see three ways doing ATAGS init for SPL:
- use bootm.c which means init bd correctly and add a bunch of #ifdef
CONFIG_PRELOADER to it - maybe also to some others i don't have on the radar yet.
While this is not clean, it might work good.
- Have ATAGS config in board config file and init it at compile time
This is a problematic approach, because memory size, board revision, serial number and may be some others are only known in runtime.
- Doing it like Heiko and copy the ATAGS config done by u-boot
This one is probably the most clean way.
The problem with approach 3 is that you need to copy the ATAGS image. Is there a way to do this without a debugger? If yes it really could be an alternative. If ATAGS and Kernel can be reflashed you can update the kernel without a bootloader update (That's the main reason why i switched to 1).
Regarding the device tree on ARM, it is still not fully functional. Nevertheless, currently there is an attempt ([1] and [2]) to make kernel work with both, device tree and ATAGS and if I understood correctly, the ATAGS will have precedence over the DT, so closed source boot loaders will still work.
[1] - http://www.spinics.net/lists/arm-kernel/msg128172.html [2] - http://www.spinics.net/lists/arm-kernel/msg129270.html
So, IMHO an ATAGS implementation for now is the better choice - a DT patch then is, depending on the approach, not a big problem.
Regards Simon

Dear Wolfgang Denk,
a comment from your side would be nice - in what approach do you see the best chance for getting it into mainline?
Regards Simon
2011/7/1 Simon Schwarz simonschwarzcor@googlemail.com:
Thanks for your feedback Igor!
2011/7/1 Igor Grinberg grinberg@compulab.co.il:
On 07/01/11 12:17, Simon Schwarz wrote:
Ok, topic ATAGS: I see three ways doing ATAGS init for SPL:
- use bootm.c which means init bd correctly and add a bunch of #ifdef
CONFIG_PRELOADER to it - maybe also to some others i don't have on the radar yet.
While this is not clean, it might work good.
- Have ATAGS config in board config file and init it at compile time
This is a problematic approach, because memory size, board revision, serial number and may be some others are only known in runtime.
- Doing it like Heiko and copy the ATAGS config done by u-boot
This one is probably the most clean way.
The problem with approach 3 is that you need to copy the ATAGS image. Is there a way to do this without a debugger? If yes it really could be an alternative. If ATAGS and Kernel can be reflashed you can update the kernel without a bootloader update (That's the main reason why i switched to 1).
Regarding the device tree on ARM, it is still not fully functional. Nevertheless, currently there is an attempt ([1] and [2]) to make kernel work with both, device tree and ATAGS and if I understood correctly, the ATAGS will have precedence over the DT, so closed source boot loaders will still work.
[1] - http://www.spinics.net/lists/arm-kernel/msg128172.html [2] - http://www.spinics.net/lists/arm-kernel/msg129270.html
So, IMHO an ATAGS implementation for now is the better choice - a DT patch then is, depending on the approach, not a big problem.
Regards Simon

Dear Simon Schwarz,
In message BANLkTikJ62qw9pnaq3HfRX7T9XwZ7p7PGA@mail.gmail.com you wrote:
a comment from your side would be nice - in what approach do you see the best chance for getting it into mainline?
I already commented (see http://article.gmane.org/gmane.comp.boot-loaders.u-boot/102491). I'm all for simple and efficient solutions - i. e. approach # 3, as used by Heiko.
Best regards,
Wolfgang Denk

Dear Simon Schwarz,
In message BANLkTikVPozuHtS92uV_H2oCmBord2d96w@mail.gmail.com you wrote:
The problem with approach 3 is that you need to copy the ATAGS image. Is there a way to do this without a debugger? If yes it really could
You will need the ATAGs image only in U-Boot, so it should be sufficient to use nand_write in U-Boot to write it to the location where you later want to load it from.
be an alternative. If ATAGS and Kernel can be reflashed you can update the kernel without a bootloader update (That's the main reason why i switched to 1).
There is no need to update the boot loader in this context.
Best regards,
Wolfgang Denk
participants (6)
-
Detlev Zundel
-
Grant Likely
-
Heiko Schocher
-
Igor Grinberg
-
Simon Schwarz
-
Wolfgang Denk