diff mbox

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

Message ID 4E0C5FE3.10300@denx.de
State Superseded
Headers show

Commit Message

Heiko Schocher June 30, 2011, 11:37 a.m. UTC
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>
---

Comments

Simon Schwarz June 30, 2011, 1:44 p.m. UTC | #1
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
Wolfgang Denk July 3, 2011, 8:42 p.m. UTC | #2
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
diff mbox

Patch

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
 }