[U-Boot] passing info from SPL to U-Boot

Heiko Schocher hs at denx.de
Fri Mar 15 05:36:23 UTC 2019


Hello Simon,

Am 14.03.2019 um 11:02 schrieb Simon Glass:
> Hi Heiko,
> 
> On Tue, 12 Mar 2019 at 02:50, Heiko Schocher <hs at denx.de> wrote:
>>
>> Hello Simon, Tom,
>>
>> Am 12.03.2019 um 09:21 schrieb Heiko Schocher:
>>> Hello Simon, Tom,
>>>
>>> I am just stumbeld on an am437x basd board over the problem to pass
>>> the bootmode from SPL to U-Boot. On am437x the bootmode info get
>>> overwritten from SPL stack, and I need this info in U-Boot.
>>>
>>> Hack would be to move SPL stack to another address, but we loose
>>> than 0xa000 size for stack ... I do not want to go this way..
>>>
>>> I thought gd info is passed from SPL to U-Boot, but this is not the case!
>>>
>>> Looking into
>>>
>>> ...
>>>    75         bic     r0, r0, #7      /* 8-byte alignment for ABI compliance */
>>>    76         mov     sp, r0
>>>    77         bl      board_init_f_alloc_reserve
>>>    78         mov     sp, r0
>>>    79         /* set up gd here, outside any C code */
>>>    80         mov     r9, r0
>>>    81         bl      board_init_f_init_reserve
>>>
>>> and common/init/board_init.c:
>>>
>>>    99 void board_init_f_init_reserve(ulong base)
>>> 100 {
>>> 101         struct global_data *gd_ptr;
>>> 102
>>> 103         /*
>>> 104          * clear GD entirely and set it up.
>>> 105          * Use gd_ptr, as gd may not be properly set yet.
>>> 106          */
>>> 107
>>> 108         gd_ptr = (struct global_data *)base;
>>> 109         /* zero the area */
>>> 110         memset(gd_ptr, '\0', sizeof(*gd));
>>> 111         /* set GD unless architecture did it already */
>>> 112 #if !defined(CONFIG_ARM)
>>> 113         arch_setup_gd(gd_ptr);
>>> 114 #endif
>>>
>>> gd is always initialized with zeros, no chance for passing infos from
>>> SPL to U-Boot...
>>>
>>> I really thought, that gd_t was intentionally designed for passing data
>>> between different U-Boot states, but looking into gd_t definiton in
>>> include/asm-generic/global_data.h it is a big ifdef mess and not useable
>>> as an "API" between TPL/SPL and U-Boot ...
>>>
>>> I thought also, that SPL detects for example ramsize and than passes
>>> this info to U-Boot ...
>>>
>>> But Ok, I found "common/init/handoff.c" which seems now the way to go, but:
>>>
>>> ./common/board_f.c
>>>
>>>    281 static int setup_spl_handoff(void)
>>>    282 {
>>>    283 #if CONFIG_IS_ENABLED(HANDOFF)
>>>    284         gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
>>>    285                                         sizeof(struct spl_handoff));
>>>    286         debug("Found SPL hand-off info %p\n", gd->spl_handoff);
>>>    287 #endif
>>>    288
>>>    289         return 0;
>>>    290 }
>>>
>>> There is gd->spl_handoff used ... how could this work at least on arm,
>>> if gd is set to zeros on init ?
>>>
>>> Do I miss something obvious?
>>
>> Sorry for being so stupid, with:
>>
>> common/board_f.c
>>
>>    853 #ifdef CONFIG_BLOBLIST
>>    854         bloblist_init,
>>    855 #endif
>>    856         setup_spl_handoff,
>>
>> and common/bloblist.c
>>
>> 216 int bloblist_init(void)
>> 217 {
>> 218         bool expected;
>> 219         int ret = -ENOENT;
>> 220
>> 221         /**
>> 222          * Wed expect to find an existing bloblist in the first phase of U-Boot
>> 223          * that runs
>> 224          */
>> 225         expected = !u_boot_first_phase();
>> 226         if (expected)
>> 227                 ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
>> 228                                      CONFIG_BLOBLIST_SIZE);
>>
>> gd->spl_handoff gets setup through bloblist_find() ...
>>
>> But beside sandbox there is no current user currently, or?
>>
>> $ grep -lr BLOBLIST_ADDR .
>> ./test/bloblist.c
>> ./include/bloblist.h
>> ./common/bloblist.c
>> ./common/Kconfig
>> ./board/sandbox/README.sandbox
>> $
> 
> Yes that's right, it is not used outside sandbox, although there are
> patches to use it on x86.

Thanks for clarifying!

> I think it is a reasonable idea to allow the gd region to pass from
> TPL -> SPL -> U-Boot. But we'll need to remove use of
> CONFIG_IS_ENABLED(), or put shared things at the beginning of the
> structure.

I thought about putting interchangeable things at the beginning
of gd_t.

The big advantage of a bloblist is, that you only need to parse it
and you know, what values are really setup from the previous stage.

Passing structs is not ideal, but small ... but may error prone?

Can we always be sure, previous stage sets up all info in gd_t
next stage expects?

> We need the concept of 'am I the first thing to run'. This is
> implemented in bloblist as u_boot_first_phase() - see spl.h. If this
> is true, we must set up the data structure. If false we must find one
> set up by a previous phase and use it. Bloblist handles this, but
> perhaps gd could as well?

Yes, this could be used.

> Also consider the scenario where there is a read-only TPL programmed
> in manufacture that never changes, and a read-write SPL +  U-Boot that
> can be upgraded in the field. In this case they may eventually end up
> being built with different versions of U-Boot. The bloblist structure
> is intended to handle this by at least checking that the size matches.

Just experimenting with:
diff --git a/common/init/board_init.c b/common/init/board_init.c
index 526fee35ff..bdb4b6364d 100644
--- a/common/init/board_init.c
+++ b/common/init/board_init.c
@@ -96,9 +96,10 @@ ulong board_init_f_alloc_reserve(ulong top)
   * (seemingly useless) incrementation causes no code increase.
   */

-void board_init_f_init_reserve(ulong base)
+void board_init_f_init_reserve(ulong base, ulong oldgd)
  {
         struct global_data *gd_ptr;
+       struct global_data *gd_ptr_old;

         /*
          * clear GD entirely and set it up.
@@ -106,8 +107,22 @@ void board_init_f_init_reserve(ulong base)
          */

         gd_ptr = (struct global_data *)base;
-       /* zero the area */
-       memset(gd_ptr, '\0', sizeof(*gd));
+       gd_ptr_old = (struct global_data *)oldgd;
+       if (u_boot_first_phase() ||
+           oldgd == 0 ||
+           !(((gd_ptr->magic == UBOOT_GD_MAGIC) &&
+                (gd_ptr->gd_size == sizeof(struct global_data))))) {
+               /* setup gd, zero the area ... */
+               memset(gd_ptr, '\0', sizeof(*gd));
+               /* ... and set magic and size information */
+               gd_ptr->magic = UBOOT_GD_MAGIC;
+               gd_ptr->gd_size = sizeof(struct global_data);
+       } else {
+               /*
+                * in case we get an already initialised gd_pointer
+                * use the info from already existing oldgd.
+                */
+       }
         /* set GD unless architecture did it already */
  #if !defined(CONFIG_ARM)
         arch_setup_gd(gd_ptr);
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 78dcf40bff..3a5063dbe1 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -23,8 +23,11 @@
  #include <membuff.h>
  #include <linux/list.h>

+#define UBOOT_GD_MAGIC 0x19730517
  typedef struct global_data {
         bd_t *bd;
+       unsigned long magic;
+       int gd_size;
         unsigned long flags;
         unsigned int baudrate;
         unsigned long cpu_clk;          /* CPU clock in Hz!             */

(after moving u_boot_first_phase() to include/common.h)

But it is WIP, nothing functional yet...

> Related, I feel that we should figure out how to use registers to pass
> addresses from SPL to U-Boot. On ARM we could use r0 to pass the value
> of gd, perhaps.

Perhaps, yes.

bye,
Heiko
-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52   Fax: +49-8142-66989-80   Email: hs at denx.de


More information about the U-Boot mailing list