
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 }